blob: d78d1e31f671dcce70cf9e468773f25ea367ff36 [file] [log] [blame]
Andy Hung06f3aba2019-12-03 16:36:42 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AudioAnalytics"
Andy Hung1ea842e2020-05-18 10:47:31 -070019#include <android-base/logging.h>
Andy Hung06f3aba2019-12-03 16:36:42 -080020#include <utils/Log.h>
21
22#include "AudioAnalytics.h"
Andy Hung1ea842e2020-05-18 10:47:31 -070023
Andy Hungce9b6632020-04-28 20:15:17 -070024#include <audio_utils/clock.h> // clock conversions
Andy Hung1ea842e2020-05-18 10:47:31 -070025#include <cutils/properties.h>
Andy Hungce9b6632020-04-28 20:15:17 -070026#include <statslog.h> // statsd
Andy Hung06f3aba2019-12-03 16:36:42 -080027
Andy Hung1ea842e2020-05-18 10:47:31 -070028#include "AudioTypes.h" // string to int conversions
29#include "MediaMetricsService.h" // package info
30#include "StringUtils.h"
31
32#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
33
Andy Hunga629bd12020-06-05 16:03:53 -070034namespace android::mediametrics {
Andy Hung1ea842e2020-05-18 10:47:31 -070035
Andy Hunga629bd12020-06-05 16:03:53 -070036// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
Andy Hunga0a5ad22020-06-12 09:30:34 -070037#define STATSD_ENABLE
Andy Hung1ea842e2020-05-18 10:47:31 -070038
Andy Hunga629bd12020-06-05 16:03:53 -070039#ifdef STATSD_ENABLE
40#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
Andy Hung1ea842e2020-05-18 10:47:31 -070041#else
Andy Hunga629bd12020-06-05 16:03:53 -070042#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
Andy Hung1ea842e2020-05-18 10:47:31 -070043#endif
44
Andy Hunga629bd12020-06-05 16:03:53 -070045// Maximum length of a device name.
Andy Hung3deef2b2020-07-17 12:58:54 -070046// static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
Andy Hung06f3aba2019-12-03 16:36:42 -080047
Andy Hunga629bd12020-06-05 16:03:53 -070048// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
49static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
50
51// derive types based on integer or strings.
52using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
53using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
54
55// Convert std::string to char *
56template <typename T>
57auto ENUM_EXTRACT(const T& x) {
58 if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
59 return x.c_str();
60 } else {
61 return x;
62 }
63}
64
65static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
66
Andy Hungb18f5062020-06-18 23:10:08 -070067static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
68
Andy Hung3deef2b2020-07-17 12:58:54 -070069static constexpr const char * SUPPRESSED = "SUPPRESSED";
70
Andy Hunga629bd12020-06-05 16:03:53 -070071/*
72 * For logging purposes, we list all of the MediaMetrics atom fields,
73 * which can then be associated with consecutive arguments to the statsd write.
74 */
75
76static constexpr const char * const AudioRecordDeviceUsageFields[] = {
77 "mediametrics_audiorecorddeviceusage_reported", // proto number
78 "devices",
79 "device_names",
80 "device_time_nanos",
81 "encoding",
82 "frame_count",
83 "interval_count",
84 "sample_rate",
85 "flags",
86 "package_name",
87 "selected_device_id",
88 "caller",
89 "source",
90};
91
92static constexpr const char * const AudioThreadDeviceUsageFields[] = {
93 "mediametrics_audiothreaddeviceusage_reported",
94 "devices",
95 "device_names",
96 "device_time_nanos",
97 "encoding",
98 "frame_count",
99 "interval_count",
100 "sample_rate",
101 "flags",
102 "xruns",
103 "type",
104};
105
106static constexpr const char * const AudioTrackDeviceUsageFields[] = {
107 "mediametrics_audiotrackdeviceusage_reported",
108 "devices",
109 "device_names",
110 "device_time_nanos",
111 "encoding",
112 "frame_count",
113 "interval_count",
114 "sample_rate",
115 "flags",
116 "xruns",
117 "package_name",
118 "device_latency_millis",
119 "device_startup_millis",
120 "device_volume",
121 "selected_device_id",
122 "stream_type",
123 "usage",
124 "content_type",
125 "caller",
126 "traits",
127};
128
129static constexpr const char * const AudioDeviceConnectionFields[] = {
130 "mediametrics_audiodeviceconnection_reported",
131 "input_devices",
132 "output_devices",
133 "device_names",
134 "result",
135 "time_to_connect_millis",
136 "connection_count",
137};
138
139/**
140 * sendToStatsd is a helper method that sends the arguments to statsd
141 * and returns a pair { result, summary_string }.
142 */
143template <size_t N, typename ...Types>
144std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
145{
146 int result = 0;
147 std::stringstream ss;
148
149#ifdef STATSD_ENABLE
150 result = android::util::stats_write(args...);
151 ss << "result:" << result;
152#endif
153 ss << " { ";
154 stringutils::fieldPrint(ss, fields, args...);
155 ss << "}";
156 return { result, ss.str() };
157}
Andy Hung06f3aba2019-12-03 16:36:42 -0800158
159AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -0700160 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -0800161{
Andy Hunga629bd12020-06-05 16:03:53 -0700162 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800163 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800164
165 // Add action to save AnalyticsState if audioserver is restarted.
166 // This triggers on an item of "audio.flinger"
167 // with a property "event" set to "AudioFlinger" (the constructor).
168 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800169 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
170 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800171 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800172 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
173 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800174 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
175 *mAnalyticsState.get()));
176 // Note: get returns shared_ptr temp, whose lifetime is extended
177 // to end of full expression.
178 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800179 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700180
181 // Set up a timer to expire the previous audio state to save space.
182 // Use the transaction log size as a cookie to see if it is the
183 // same as before. A benign race is possible where a state is cleared early.
184 const size_t size = mPreviousAnalyticsState->transactionLog().size();
185 mTimedAction.postIn(
186 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
187 if (mPreviousAnalyticsState->transactionLog().size() == size) {
188 ALOGD("expiring previous audio state after %d seconds.",
189 PREVIOUS_STATE_EXPIRE_SEC);
190 mPreviousAnalyticsState->clear(); // removes data from the state.
191 }
192 });
Andy Hungea186fa2020-01-09 18:13:15 -0800193 }));
194
Andy Hungea840382020-05-05 21:50:17 -0700195 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800196 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700197 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
198 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800199 std::make_shared<AnalyticsActions::Function>(
200 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700201 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800202 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700203
204 // Handle device use thread statistics
205 mActions.addAction(
206 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
207 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
208 std::make_shared<AnalyticsActions::Function>(
209 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700210 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700211 }));
212
213 // Handle device use track statistics
214 mActions.addAction(
215 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
216 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
217 std::make_shared<AnalyticsActions::Function>(
218 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700219 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700220 }));
221
Andy Hungea840382020-05-05 21:50:17 -0700222
223 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700224
225 // We track connections (not disconnections) for the time to connect.
226 // TODO: consider BT requests in their A2dp service
227 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
228 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
229 // AudioDeviceBroker.postA2dpActiveDeviceChange
230 mActions.addAction(
231 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700232 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700233 std::make_shared<AnalyticsActions::Function>(
234 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
235 mDeviceConnection.a2dpConnected(item);
236 }));
237 // If audio is active, we expect to see a createAudioPatch after the device is connected.
238 mActions.addAction(
239 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
240 std::string("createAudioPatch"),
241 std::make_shared<AnalyticsActions::Function>(
242 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
243 mDeviceConnection.createPatch(item);
244 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800245
Andy Hungea840382020-05-05 21:50:17 -0700246 // Called from BT service
247 mActions.addAction(
248 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
249 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
250 "." AMEDIAMETRICS_PROP_STATE,
251 "connected",
252 std::make_shared<AnalyticsActions::Function>(
253 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
254 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
255 }));
256
Joey Poomarin52989982020-03-05 17:40:49 +0800257 // Handle power usage
258 mActions.addAction(
259 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
260 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
261 std::make_shared<AnalyticsActions::Function>(
262 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
263 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
264 }));
265
266 mActions.addAction(
267 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
268 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
269 std::make_shared<AnalyticsActions::Function>(
270 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
271 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
272 }));
273
274 mActions.addAction(
275 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
276 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
277 std::make_shared<AnalyticsActions::Function>(
278 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
279 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
280 mAudioPowerUsage.checkMode(item);
281 }));
282
283 mActions.addAction(
284 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
285 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
286 std::make_shared<AnalyticsActions::Function>(
287 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
288 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
289 mAudioPowerUsage.checkVoiceVolume(item);
290 }));
291
292 mActions.addAction(
293 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
294 std::string("createAudioPatch"),
295 std::make_shared<AnalyticsActions::Function>(
296 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
297 mAudioPowerUsage.checkCreatePatch(item);
298 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800299}
300
301AudioAnalytics::~AudioAnalytics()
302{
303 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700304 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800305}
306
307status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800308 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800309{
Andy Hungea186fa2020-01-09 18:13:15 -0800310 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800311 status_t status = mAnalyticsState->submit(item, isTrusted);
312 if (status != NO_ERROR) return status; // may not be permitted.
313
314 // Only if the item was successfully submitted (permission)
315 // do we check triggered actions.
316 checkActions(item);
317 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800318}
319
Andy Hung709b91e2020-04-04 14:23:36 -0700320std::pair<std::string, int32_t> AudioAnalytics::dump(
321 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800322{
323 std::stringstream ss;
324 int32_t ll = lines;
325
326 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700327 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700328 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800329 ll -= l;
330 }
331 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800332 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800333 --ll;
334 }
335 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700336 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700337 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800338 ll -= l;
339 }
Joey Poomarin52989982020-03-05 17:40:49 +0800340
Andy Hunga629bd12020-06-05 16:03:53 -0700341 if (ll > 0) {
342 // Print the statsd atoms we sent out.
343 const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
344 const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
345 if ((size_t)ll >= n) {
346 if (n == 1) {
347 ss << "Statsd atoms: empty or truncated\n";
348 } else {
349 ss << "Statsd atoms:\n" << statsd;
350 }
351 ll -= n;
352 }
353 }
354
Joey Poomarin52989982020-03-05 17:40:49 +0800355 if (ll > 0 && prefix == nullptr) {
356 auto [s, l] = mAudioPowerUsage.dump(ll);
357 ss << s;
358 ll -= l;
359 }
Andy Hunga629bd12020-06-05 16:03:53 -0700360
Andy Hung06f3aba2019-12-03 16:36:42 -0800361 return { ss.str(), lines - ll };
362}
363
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800364void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
365{
366 auto actions = mActions.getActionsForItem(item); // internally locked.
367 // Execute actions with no lock held.
368 for (const auto& action : actions) {
369 (*action)(item);
370 }
371}
372
Andy Hungea186fa2020-01-09 18:13:15 -0800373// HELPER METHODS
374
375std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
376{
377 int32_t threadId_int32{};
378 if (mAnalyticsState->timeMachine().get(
379 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
380 return {};
381 }
382 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
383}
384
Andy Hungce9b6632020-04-28 20:15:17 -0700385// DeviceUse helper class.
386void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700387 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700388 const std::string& key = item->getKey();
389 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700390 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
391 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
392 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700393 - 1);
394 // deliver statistics
395 int64_t deviceTimeNs = 0;
396 mAudioAnalytics.mAnalyticsState->timeMachine().get(
397 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
398 std::string encoding;
399 mAudioAnalytics.mAnalyticsState->timeMachine().get(
400 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
401 int32_t frameCount = 0;
402 mAudioAnalytics.mAnalyticsState->timeMachine().get(
403 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700404 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700405 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700406 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700407 int32_t intervalCount = 0;
408 mAudioAnalytics.mAnalyticsState->timeMachine().get(
409 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700410 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700411 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700412 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700413 int32_t sampleRate = 0;
414 mAudioAnalytics.mAnalyticsState->timeMachine().get(
415 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700416 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700417 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700418 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700419
Andy Hungea840382020-05-05 21:50:17 -0700420 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700421 // Accumulate the bit flags for input and output devices.
422 std::stringstream oss;
423 long_enum_type_t outputDeviceBits{};
424 { // compute outputDevices
425 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700426 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700427 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
428 oss << device;
429 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700430 }
431 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700432 const std::string outputDevices = oss.str();
433
434 std::stringstream iss;
435 long_enum_type_t inputDeviceBits{};
436 { // compute inputDevices
437 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
438 for (const auto& [device, addr] : devaddrvec) {
439 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
440 iss << device;
441 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
442 }
443 }
444 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700445
446 // Get connected device name if from bluetooth.
447 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700448
449 std::string inputDeviceNames; // not filled currently.
450 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700451 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
452 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700453 outputDeviceNames = SUPPRESSED;
454#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700455 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700456 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700457 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700458 stringutils::replace(outputDeviceNames, "|", '?');
459 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
460 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
461 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700462#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700463 }
464
Andy Hungea840382020-05-05 21:50:17 -0700465 switch (itemType) {
466 case RECORD: {
467 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700468 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
469 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700470
Andy Hungea840382020-05-05 21:50:17 -0700471 std::string packageName;
472 int64_t versionCode = 0;
473 int32_t uid = -1;
474 mAudioAnalytics.mAnalyticsState->timeMachine().get(
475 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
476 if (uid != -1) {
477 std::tie(packageName, versionCode) =
478 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
479 }
480
481 int32_t selectedDeviceId = 0;
482 mAudioAnalytics.mAnalyticsState->timeMachine().get(
483 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
484 std::string source;
485 mAudioAnalytics.mAnalyticsState->timeMachine().get(
486 key, AMEDIAMETRICS_PROP_SOURCE, &source);
487
Andy Hung1ea842e2020-05-18 10:47:31 -0700488 const auto callerNameForStats =
489 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
490 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
491 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
492 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungea840382020-05-05 21:50:17 -0700493
Andy Hunga629bd12020-06-05 16:03:53 -0700494 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700495 << " id:" << id
496 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700497 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700498 << " deviceTimeNs:" << deviceTimeNs
499 << " encoding:" << encoding << "(" << encodingForStats
500 << ") frameCount:" << frameCount
501 << " intervalCount:" << intervalCount
502 << " sampleRate:" << sampleRate
503 << " flags:" << flags << "(" << flagsForStats
504 << ") packageName:" << packageName
505 << " selectedDeviceId:" << selectedDeviceId
506 << " callerName:" << callerName << "(" << callerNameForStats
507 << ") source:" << source << "(" << sourceForStats << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700508 if (clientCalled // only log if client app called AudioRecord.
509 && mAudioAnalytics.mDeliverStatistics) {
510 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
511 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700512 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700513 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700514 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700515 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700516 , frameCount
517 , intervalCount
518 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700519 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700520
521 , packageName.c_str()
522 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700523 , ENUM_EXTRACT(callerNameForStats)
524 , ENUM_EXTRACT(sourceForStats)
Andy Hungea840382020-05-05 21:50:17 -0700525 );
Andy Hunga629bd12020-06-05 16:03:53 -0700526 ALOGV("%s: statsd %s", __func__, str.c_str());
527 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700528 }
Andy Hungea840382020-05-05 21:50:17 -0700529 } break;
530 case THREAD: {
531 std::string type;
532 mAudioAnalytics.mAnalyticsState->timeMachine().get(
533 key, AMEDIAMETRICS_PROP_TYPE, &type);
534 int32_t underrun = 0; // zero for record types
535 mAudioAnalytics.mAnalyticsState->timeMachine().get(
536 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700537
538 const bool isInput = types::isInputThreadType(type);
539 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
540 const auto flagsForStats =
541 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
542 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
543 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
544
Andy Hunga629bd12020-06-05 16:03:53 -0700545 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700546 << " id:" << id
547 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
548 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700549 << ") inputDeviceNames:" << inputDeviceNames
550 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700551 << " deviceTimeNs:" << deviceTimeNs
552 << " encoding:" << encoding << "(" << encodingForStats
553 << ") frameCount:" << frameCount
554 << " intervalCount:" << intervalCount
555 << " sampleRate:" << sampleRate
556 << " underrun:" << underrun
557 << " flags:" << flags << "(" << flagsForStats
558 << ") type:" << type << "(" << typeForStats
559 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700560 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700561 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
562 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
563 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
564 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700565 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700566 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700567 , frameCount
568 , intervalCount
569 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700570 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700571 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700572 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700573 );
Andy Hunga629bd12020-06-05 16:03:53 -0700574 ALOGV("%s: statsd %s", __func__, str.c_str());
575 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700576 }
Andy Hungea840382020-05-05 21:50:17 -0700577 } break;
578 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700579 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700580 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
581 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
582
Andy Hungce9b6632020-04-28 20:15:17 -0700583 std::string contentType;
584 mAudioAnalytics.mAnalyticsState->timeMachine().get(
585 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
586 double deviceLatencyMs = 0.;
587 mAudioAnalytics.mAnalyticsState->timeMachine().get(
588 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
589 double deviceStartupMs = 0.;
590 mAudioAnalytics.mAnalyticsState->timeMachine().get(
591 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
592 double deviceVolume = 0.;
593 mAudioAnalytics.mAnalyticsState->timeMachine().get(
594 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
595 std::string packageName;
596 int64_t versionCode = 0;
597 int32_t uid = -1;
598 mAudioAnalytics.mAnalyticsState->timeMachine().get(
599 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
600 if (uid != -1) {
601 std::tie(packageName, versionCode) =
602 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
603 }
604 double playbackPitch = 0.;
605 mAudioAnalytics.mAnalyticsState->timeMachine().get(
606 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
607 double playbackSpeed = 0.;
608 mAudioAnalytics.mAnalyticsState->timeMachine().get(
609 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
610 int32_t selectedDeviceId = 0;
611 mAudioAnalytics.mAnalyticsState->timeMachine().get(
612 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700613 std::string streamType;
614 mAudioAnalytics.mAnalyticsState->timeMachine().get(
615 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700616 std::string traits;
617 mAudioAnalytics.mAnalyticsState->timeMachine().get(
618 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700619 int32_t underrun = 0;
620 mAudioAnalytics.mAnalyticsState->timeMachine().get(
621 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700622 std::string usage;
623 mAudioAnalytics.mAnalyticsState->timeMachine().get(
624 key, AMEDIAMETRICS_PROP_USAGE, &usage);
625
Andy Hung1ea842e2020-05-18 10:47:31 -0700626 const auto callerNameForStats =
627 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
628 const auto contentTypeForStats =
629 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
630 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
631 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
632 const auto streamTypeForStats =
633 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700634 const auto traitsForStats =
635 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700636 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
637
Andy Hunga629bd12020-06-05 16:03:53 -0700638 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700639 << " id:" << id
640 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700641 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700642 << " deviceTimeNs:" << deviceTimeNs
643 << " encoding:" << encoding << "(" << encodingForStats
644 << ") frameCount:" << frameCount
645 << " intervalCount:" << intervalCount
646 << " sampleRate:" << sampleRate
647 << " underrun:" << underrun
648 << " flags:" << flags << "(" << flagsForStats
649 << ") callerName:" << callerName << "(" << callerNameForStats
650 << ") contentType:" << contentType << "(" << contentTypeForStats
651 << ") deviceLatencyMs:" << deviceLatencyMs
652 << " deviceStartupMs:" << deviceStartupMs
653 << " deviceVolume:" << deviceVolume
654 << " packageName:" << packageName
655 << " playbackPitch:" << playbackPitch
656 << " playbackSpeed:" << playbackSpeed
657 << " selectedDeviceId:" << selectedDeviceId
658 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700659 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700660 << ") usage:" << usage << "(" << usageForStats
661 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700662 if (clientCalled // only log if client app called AudioTracks
663 && mAudioAnalytics.mDeliverStatistics) {
664 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
665 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700666 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700667 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700668 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700669 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700670 , frameCount
671 , intervalCount
672 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700673 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700674 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700675 , packageName.c_str()
676 , (float)deviceLatencyMs
677 , (float)deviceStartupMs
678 , (float)deviceVolume
679 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700680 , ENUM_EXTRACT(streamTypeForStats)
681 , ENUM_EXTRACT(usageForStats)
682 , ENUM_EXTRACT(contentTypeForStats)
683 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700684 , ENUM_EXTRACT(traitsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700685 );
Andy Hunga629bd12020-06-05 16:03:53 -0700686 ALOGV("%s: statsd %s", __func__, str.c_str());
687 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700688 }
Andy Hungea840382020-05-05 21:50:17 -0700689 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700690 }
691
692 // Report this as needed.
693 if (isBluetooth) {
694 // report this for Bluetooth
695 }
696}
697
698// DeviceConnection helper class.
699void AudioAnalytics::DeviceConnection::a2dpConnected(
700 const std::shared_ptr<const android::mediametrics::Item> &item) {
701 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700702 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700703 {
704 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700705 mA2dpConnectionServiceNs = atNs;
706 ++mA2dpConnectionServices;
707
708 if (mA2dpConnectionRequestNs == 0) {
709 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
710 }
711 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700712 }
713 std::string name;
714 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700715 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
716 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700717}
718
719void AudioAnalytics::DeviceConnection::createPatch(
720 const std::shared_ptr<const android::mediametrics::Item> &item) {
721 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700722 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700723 const std::string& key = item->getKey();
724 std::string outputDevices;
725 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700726 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700727 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700728 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700729 if (mA2dpConnectionRequestNs == 0) {
730 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700731 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700732 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700733 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700734 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700735
Andy Hungea840382020-05-05 21:50:17 -0700736 mA2dpConnectionRequestNs = 0;
737 mA2dpConnectionServiceNs = 0;
738 ++mA2dpConnectionSuccesses;
739
Andy Hung1ea842e2020-05-18 10:47:31 -0700740 const auto connectionTimeMs = float(timeDiffNs * 1e-6);
741
742 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
743 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
744
Andy Hunga629bd12020-06-05 16:03:53 -0700745 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700746 << " A2DP SUCCESS"
747 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700748 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700749 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700750 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700751 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700752
753 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
754 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700755 , ENUM_EXTRACT(inputDeviceBits)
756 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700757 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700758 , types::DEVICE_CONNECTION_RESULT_SUCCESS
759 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700760 , /* connection_count */ 1
761 );
Andy Hunga629bd12020-06-05 16:03:53 -0700762 ALOGV("%s: statsd %s", __func__, str.c_str());
763 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700764 }
Andy Hungce9b6632020-04-28 20:15:17 -0700765 }
766}
767
Andy Hungea840382020-05-05 21:50:17 -0700768// Called through AudioManager when the BT service wants to enable
769void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
770 const std::shared_ptr<const android::mediametrics::Item> &item) {
771 const int64_t atNs = item->getTimestamp();
772 const std::string& key = item->getKey();
773 std::string state;
774 item->get(AMEDIAMETRICS_PROP_STATE, &state);
775 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700776
777 std::string name;
778 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700779 {
780 std::lock_guard l(mLock);
781 mA2dpConnectionRequestNs = atNs;
782 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700783 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700784 }
Andy Hunga629bd12020-06-05 16:03:53 -0700785 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
786 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700787 // TODO: attempt to cancel a timed event, rather than let it expire.
788 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
789}
790
Andy Hungce9b6632020-04-28 20:15:17 -0700791void AudioAnalytics::DeviceConnection::expire() {
792 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700793 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700794
Andy Hung1ea842e2020-05-18 10:47:31 -0700795 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700796 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
797 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
798
Andy Hungea840382020-05-05 21:50:17 -0700799 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700800 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700801
Andy Hunga629bd12020-06-05 16:03:53 -0700802 LOG(LOG_LEVEL) << "A2DP CANCEL"
803 << " outputDevices:" << outputDeviceBits
804 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700805 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700806 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
807 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700808 , ENUM_EXTRACT(inputDeviceBits)
809 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700810 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700811 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700812 , /* connection_time_ms */ 0.f
813 , /* connection_count */ 1
814 );
Andy Hunga629bd12020-06-05 16:03:53 -0700815 ALOGV("%s: statsd %s", __func__, str.c_str());
816 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700817 }
Andy Hungea840382020-05-05 21:50:17 -0700818 return;
819 }
820
821 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
822 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700823 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700824 mA2dpConnectionRequestNs = 0;
825 mA2dpConnectionServiceNs = 0;
826 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700827
Andy Hunga629bd12020-06-05 16:03:53 -0700828 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
829 << " outputDevices:" << outputDeviceBits
830 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700831 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700832 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
833 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700834 , ENUM_EXTRACT(inputDeviceBits)
835 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700836 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700837 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700838 , /* connection_time_ms */ 0.f
839 , /* connection_count */ 1
840 );
Andy Hunga629bd12020-06-05 16:03:53 -0700841 ALOGV("%s: statsd %s", __func__, str.c_str());
842 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700843 }
Andy Hungce9b6632020-04-28 20:15:17 -0700844}
845
Andy Hung3ab1b322020-05-18 10:47:31 -0700846} // namespace android::mediametrics