• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
19 #include <android-base/logging.h>
20 #include <utils/Log.h>
21 
22 #include "AudioAnalytics.h"
23 
24 #include <audio_utils/clock.h>    // clock conversions
25 #include <cutils/properties.h>
26 #include <statslog.h>             // statsd
27 #include <system/audio.h>
28 
29 #include "AudioTypes.h"           // string to int conversions
30 #include "MediaMetricsService.h"  // package info
31 #include "StringUtils.h"
32 
33 #define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
34 
35 namespace android::mediametrics {
36 
37 // Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
38 #define STATSD_ENABLE
39 
40 #ifdef STATSD_ENABLE
41 #define CONDITION(INT_VALUE) (INT_VALUE)  // allow value
42 #else
43 #define CONDITION(INT_VALUE) (int(0))     // mask value since the proto may not be defined yet.
44 #endif
45 
46 // Maximum length of a device name.
47 // static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
48 
49 // Transmit Enums to statsd in integer or strings  (this must match the atoms.proto)
50 static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
51 
52 // derive types based on integer or strings.
53 using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
54 using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
55 
56 // Convert std::string to char *
57 template <typename T>
ENUM_EXTRACT(const T & x)58 auto ENUM_EXTRACT(const T& x) {
59     if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
60         return x.c_str();
61     } else {
62         return x;
63     }
64 }
65 
66 static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
67 
68 static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
69 
70 static constexpr const char * SUPPRESSED = "SUPPRESSED";
71 
72 /*
73  * For logging purposes, we list all of the MediaMetrics atom fields,
74  * which can then be associated with consecutive arguments to the statsd write.
75  */
76 
77 static constexpr const char * const AudioRecordDeviceUsageFields[] = {
78     "mediametrics_audiorecorddeviceusage_reported", // proto number
79     "devices",
80     "device_names",
81     "device_time_nanos",
82     "encoding",
83     "frame_count",
84     "interval_count",
85     "sample_rate",
86     "flags",
87     "package_name",
88     "selected_device_id",
89     "caller",
90     "source",
91     "log_session_id",
92 };
93 
94 static constexpr const char * const AudioThreadDeviceUsageFields[] = {
95     "mediametrics_audiothreaddeviceusage_reported",
96     "devices",
97     "device_names",
98     "device_time_nanos",
99     "encoding",
100     "frame_count",
101     "interval_count",
102     "sample_rate",
103     "flags",
104     "xruns",
105     "type",
106 };
107 
108 static constexpr const char * const AudioTrackDeviceUsageFields[] = {
109     "mediametrics_audiotrackdeviceusage_reported",
110     "devices",
111     "device_names",
112     "device_time_nanos",
113     "encoding",
114     "frame_count",
115     "interval_count",
116     "sample_rate",
117     "flags",
118     "xruns",
119     "package_name",
120     "device_latency_millis",
121     "device_startup_millis",
122     "device_volume",
123     "selected_device_id",
124     "stream_type",
125     "usage",
126     "content_type",
127     "caller",
128     "traits",
129     "log_session_id",
130 };
131 
132 static constexpr const char * const AudioDeviceConnectionFields[] = {
133     "mediametrics_audiodeviceconnection_reported",
134     "input_devices",
135     "output_devices",
136     "device_names",
137     "result",
138     "time_to_connect_millis",
139     "connection_count",
140 };
141 
142 static constexpr const char * const AAudioStreamFields[] {
143     "mediametrics_aaudiostream_reported",
144     "path",
145     "direction",
146     "frames_per_burst",
147     "buffer_size",
148     "buffer_capacity",
149     "channel_count",
150     "total_frames_transferred",
151     "perf_mode_requested",
152     "perf_mode_actual",
153     "sharing",
154     "xrun_count",
155     "device_type",
156     "format_app",
157     "format_device",
158     "log_session_id",
159     "sample_rate",
160     "content_type",
161     "sharing_requested",
162 };
163 
164 /**
165  * printFields is a helper method that prints the fields and corresponding values
166  * in a human readable style.
167  */
168 template <size_t N, typename ...Types>
printFields(const char * const (& fields)[N],Types...args)169 std::string printFields(const char * const (& fields)[N], Types ... args)
170 {
171     std::stringstream ss;
172     ss << " { ";
173     stringutils::fieldPrint(ss, fields, args...);
174     ss << "}";
175     return ss.str();
176 }
177 
178 /**
179  * sendToStatsd is a helper method that sends the arguments to statsd
180  */
181 template <typename ...Types>
sendToStatsd(Types...args)182 int sendToStatsd(Types ... args)
183 {
184     int result = 0;
185 
186 #ifdef STATSD_ENABLE
187     result = android::util::stats_write(args...);
188 #endif
189     return result;
190 }
191 
192 /**
193  * sendToStatsd is a helper method that sends the arguments to statsd
194  * and returns a pair { result, summary_string }.
195  */
196 template <size_t N, typename ...Types>
sendToStatsd(const char * const (& fields)[N],Types...args)197 std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
198 {
199     int result = 0;
200     std::stringstream ss;
201 
202 #ifdef STATSD_ENABLE
203     result = android::util::stats_write(args...);
204     ss << "result:" << result;
205 #endif
206     ss << " { ";
207     stringutils::fieldPrint(ss, fields, args...);
208     ss << "}";
209     return { result, ss.str() };
210 }
211 
AudioAnalytics(const std::shared_ptr<StatsdLog> & statsdLog)212 AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
213     : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
214     , mStatsdLog(statsdLog)
215     , mAudioPowerUsage(this, statsdLog)
216 {
217     SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
218     ALOGD("%s", __func__);
219 
220     // Add action to save AnalyticsState if audioserver is restarted.
221     // This triggers on an item of "audio.flinger"
222     // with a property "event" set to "AudioFlinger" (the constructor).
223     mActions.addAction(
224         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
225         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
226         std::make_shared<AnalyticsActions::Function>(
227             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
228                 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
229                 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
230                         *mAnalyticsState.get()));
231                 // Note: get returns shared_ptr temp, whose lifetime is extended
232                 // to end of full expression.
233                 mAnalyticsState->clear();  // TODO: filter the analytics state.
234                 // Perhaps report this.
235 
236                 // Set up a timer to expire the previous audio state to save space.
237                 // Use the transaction log size as a cookie to see if it is the
238                 // same as before.  A benign race is possible where a state is cleared early.
239                 const size_t size = mPreviousAnalyticsState->transactionLog().size();
240                 mTimedAction.postIn(
241                         std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
242                     if (mPreviousAnalyticsState->transactionLog().size() == size) {
243                         ALOGD("expiring previous audio state after %d seconds.",
244                                 PREVIOUS_STATE_EXPIRE_SEC);
245                         mPreviousAnalyticsState->clear();  // removes data from the state.
246                     }
247                 });
248             }));
249 
250     // Handle legacy aaudio playback stream statistics
251     mActions.addAction(
252         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
253         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
254         std::make_shared<AnalyticsActions::Function>(
255             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
256                 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
257             }));
258 
259     // Handle legacy aaudio capture stream statistics
260     mActions.addAction(
261         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
262         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
263         std::make_shared<AnalyticsActions::Function>(
264             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
265                 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
266             }));
267 
268     // Handle mmap aaudio stream statistics
269     mActions.addAction(
270         AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
271         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
272         std::make_shared<AnalyticsActions::Function>(
273             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
274                 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
275             }));
276 
277     // Handle device use record statistics
278     mActions.addAction(
279         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
280         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
281         std::make_shared<AnalyticsActions::Function>(
282             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
283                 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
284             }));
285 
286     // Handle device use thread statistics
287     mActions.addAction(
288         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
289         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
290         std::make_shared<AnalyticsActions::Function>(
291             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
292                 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
293             }));
294 
295     // Handle device use track statistics
296     mActions.addAction(
297         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
298         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
299         std::make_shared<AnalyticsActions::Function>(
300             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
301                 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
302             }));
303 
304 
305     // Handle device connection statistics
306 
307     // We track connections (not disconnections) for the time to connect.
308     // TODO: consider BT requests in their A2dp service
309     // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
310     // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
311     // AudioDeviceBroker.postA2dpActiveDeviceChange
312     mActions.addAction(
313         "audio.device.a2dp.state",
314         "connected",
315         std::make_shared<AnalyticsActions::Function>(
316             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
317                 mDeviceConnection.a2dpConnected(item);
318             }));
319     // If audio is active, we expect to see a createAudioPatch after the device is connected.
320     mActions.addAction(
321         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
322         std::string("createAudioPatch"),
323         std::make_shared<AnalyticsActions::Function>(
324             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
325                 mDeviceConnection.createPatch(item);
326             }));
327 
328     // Called from BT service
329     mActions.addAction(
330         AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
331         "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
332         "." AMEDIAMETRICS_PROP_STATE,
333         "connected",
334         std::make_shared<AnalyticsActions::Function>(
335             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
336                 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
337             }));
338 
339     // Handle power usage
340     mActions.addAction(
341         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
342         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
343         std::make_shared<AnalyticsActions::Function>(
344             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
345                 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
346             }));
347 
348     mActions.addAction(
349         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
350         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
351         std::make_shared<AnalyticsActions::Function>(
352             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
353                 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
354             }));
355 
356     mActions.addAction(
357         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
358         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
359         std::make_shared<AnalyticsActions::Function>(
360             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
361                 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
362                 mAudioPowerUsage.checkMode(item);
363             }));
364 
365     mActions.addAction(
366         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
367         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
368         std::make_shared<AnalyticsActions::Function>(
369             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
370                 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
371                 mAudioPowerUsage.checkVoiceVolume(item);
372             }));
373 
374     mActions.addAction(
375         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
376         std::string("createAudioPatch"),
377         std::make_shared<AnalyticsActions::Function>(
378             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
379                 mAudioPowerUsage.checkCreatePatch(item);
380             }));
381 }
382 
~AudioAnalytics()383 AudioAnalytics::~AudioAnalytics()
384 {
385     ALOGD("%s", __func__);
386     mTimedAction.quit(); // ensure no deferred access during destructor.
387 }
388 
submit(const std::shared_ptr<const mediametrics::Item> & item,bool isTrusted)389 status_t AudioAnalytics::submit(
390         const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
391 {
392     if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
393     status_t status = mAnalyticsState->submit(item, isTrusted);
394     if (status != NO_ERROR) return status;  // may not be permitted.
395 
396     // Only if the item was successfully submitted (permission)
397     // do we check triggered actions.
398     checkActions(item);
399     return NO_ERROR;
400 }
401 
dump(int32_t lines,int64_t sinceNs,const char * prefix) const402 std::pair<std::string, int32_t> AudioAnalytics::dump(
403         int32_t lines, int64_t sinceNs, const char *prefix) const
404 {
405     std::stringstream ss;
406     int32_t ll = lines;
407 
408     if (ll > 0) {
409         auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
410         ss << s;
411         ll -= l;
412     }
413     if (ll > 0) {
414         ss << "Prior audioserver state:\n";
415         --ll;
416     }
417     if (ll > 0) {
418         auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
419         ss << s;
420         ll -= l;
421     }
422 
423     if (ll > 0 && prefix == nullptr) {
424         auto [s, l] = mAudioPowerUsage.dump(ll);
425         ss << s;
426         ll -= l;
427     }
428 
429     return { ss.str(), lines - ll };
430 }
431 
checkActions(const std::shared_ptr<const mediametrics::Item> & item)432 void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
433 {
434     auto actions = mActions.getActionsForItem(item); // internally locked.
435     // Execute actions with no lock held.
436     for (const auto& action : actions) {
437         (*action)(item);
438     }
439 }
440 
441 // HELPER METHODS
442 
getThreadFromTrack(const std::string & track) const443 std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
444 {
445     int32_t threadId_int32{};
446     if (mAnalyticsState->timeMachine().get(
447             track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
448         return {};
449     }
450     return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
451 }
452 
453 // DeviceUse helper class.
endAudioIntervalGroup(const std::shared_ptr<const android::mediametrics::Item> & item,ItemType itemType) const454 void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
455        const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
456     const std::string& key = item->getKey();
457     const std::string id = key.substr(
458             (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
459             : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
460             : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
461              - 1);
462     // deliver statistics
463     int64_t deviceTimeNs = 0;
464     mAudioAnalytics.mAnalyticsState->timeMachine().get(
465             key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
466     std::string encoding;
467     mAudioAnalytics.mAnalyticsState->timeMachine().get(
468             key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
469     int32_t frameCount = 0;
470     mAudioAnalytics.mAnalyticsState->timeMachine().get(
471             key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
472     std::string inputDevicePairs;
473     mAudioAnalytics.mAnalyticsState->timeMachine().get(
474             key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
475     int32_t intervalCount = 0;
476     mAudioAnalytics.mAnalyticsState->timeMachine().get(
477             key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
478     std::string outputDevicePairs;
479     mAudioAnalytics.mAnalyticsState->timeMachine().get(
480             key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
481     int32_t sampleRate = 0;
482     mAudioAnalytics.mAnalyticsState->timeMachine().get(
483             key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
484     std::string flags;
485     mAudioAnalytics.mAnalyticsState->timeMachine().get(
486             key, AMEDIAMETRICS_PROP_FLAGS, &flags);
487 
488     // We may have several devices.
489     // Accumulate the bit flags for input and output devices.
490     std::stringstream oss;
491     long_enum_type_t outputDeviceBits{};
492     {   // compute outputDevices
493         const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
494         for (const auto& [device, addr] : devaddrvec) {
495             if (oss.tellp() > 0) oss << "|";  // delimit devices with '|'.
496             oss << device;
497             outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
498         }
499     }
500     const std::string outputDevices = oss.str();
501 
502     std::stringstream iss;
503     long_enum_type_t inputDeviceBits{};
504     {   // compute inputDevices
505         const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
506         for (const auto& [device, addr] : devaddrvec) {
507             if (iss.tellp() > 0) iss << "|";  // delimit devices with '|'.
508             iss << device;
509             inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
510         }
511     }
512     const std::string inputDevices = iss.str();
513 
514     // Get connected device name if from bluetooth.
515     bool isBluetooth = false;
516 
517     std::string inputDeviceNames;  // not filled currently.
518     std::string outputDeviceNames;
519     if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
520         isBluetooth = true;
521         outputDeviceNames = SUPPRESSED;
522 #if 0   // TODO(b/161554630) sanitize name
523         mAudioAnalytics.mAnalyticsState->timeMachine().get(
524             "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
525         // Remove | if present
526         stringutils::replace(outputDeviceNames, "|", '?');
527         if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
528             outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
529         }
530 #endif
531     }
532 
533     switch (itemType) {
534     case RECORD: {
535         std::string callerName;
536         const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
537                 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
538 
539         std::string packageName;
540         int64_t versionCode = 0;
541         int32_t uid = -1;
542         mAudioAnalytics.mAnalyticsState->timeMachine().get(
543                 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
544         if (uid != -1) {
545             std::tie(packageName, versionCode) =
546                     MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
547         }
548 
549         int32_t selectedDeviceId = 0;
550         mAudioAnalytics.mAnalyticsState->timeMachine().get(
551                 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
552         std::string source;
553         mAudioAnalytics.mAnalyticsState->timeMachine().get(
554                 key, AMEDIAMETRICS_PROP_SOURCE, &source);
555         // Android S
556         std::string logSessionId;
557         mAudioAnalytics.mAnalyticsState->timeMachine().get(
558                 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
559 
560         const auto callerNameForStats =
561                 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
562         const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
563         const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
564         const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
565         // Android S
566         const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
567 
568         LOG(LOG_LEVEL) << "key:" << key
569               << " id:" << id
570               << " inputDevices:" << inputDevices << "(" << inputDeviceBits
571               << ") inputDeviceNames:" << inputDeviceNames
572               << " deviceTimeNs:" << deviceTimeNs
573               << " encoding:" << encoding << "(" << encodingForStats
574               << ") frameCount:" << frameCount
575               << " intervalCount:" << intervalCount
576               << " sampleRate:" << sampleRate
577               << " flags:" << flags << "(" << flagsForStats
578               << ") packageName:" << packageName
579               << " selectedDeviceId:" << selectedDeviceId
580               << " callerName:" << callerName << "(" << callerNameForStats
581               << ") source:" << source << "(" << sourceForStats
582               << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
583               << ")";
584         if (clientCalled  // only log if client app called AudioRecord.
585                 && mAudioAnalytics.mDeliverStatistics) {
586             const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
587                     CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
588                     , ENUM_EXTRACT(inputDeviceBits)
589                     , inputDeviceNames.c_str()
590                     , deviceTimeNs
591                     , ENUM_EXTRACT(encodingForStats)
592                     , frameCount
593                     , intervalCount
594                     , sampleRate
595                     , ENUM_EXTRACT(flagsForStats)
596 
597                     , packageName.c_str()
598                     , selectedDeviceId
599                     , ENUM_EXTRACT(callerNameForStats)
600                     , ENUM_EXTRACT(sourceForStats)
601                     , logSessionIdForStats.c_str()
602                     );
603             ALOGV("%s: statsd %s", __func__, str.c_str());
604             mAudioAnalytics.mStatsdLog->log(
605                     android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
606         }
607     } break;
608     case THREAD: {
609         std::string type;
610         mAudioAnalytics.mAnalyticsState->timeMachine().get(
611                 key, AMEDIAMETRICS_PROP_TYPE, &type);
612         int32_t underrun = 0; // zero for record types
613         mAudioAnalytics.mAnalyticsState->timeMachine().get(
614                 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
615 
616         const bool isInput = types::isInputThreadType(type);
617         const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
618         const auto flagsForStats =
619                 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
620                         : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
621         const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
622 
623         LOG(LOG_LEVEL) << "key:" << key
624               << " id:" << id
625               << " inputDevices:" << inputDevices << "(" << inputDeviceBits
626               << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
627               << ") inputDeviceNames:" << inputDeviceNames
628               << " outputDeviceNames:" << outputDeviceNames
629               << " deviceTimeNs:" << deviceTimeNs
630               << " encoding:" << encoding << "(" << encodingForStats
631               << ") frameCount:" << frameCount
632               << " intervalCount:" << intervalCount
633               << " sampleRate:" << sampleRate
634               << " underrun:" << underrun
635               << " flags:" << flags << "(" << flagsForStats
636               << ") type:" << type << "(" << typeForStats
637               << ")";
638         if (mAudioAnalytics.mDeliverStatistics) {
639             const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
640                 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
641                 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
642                 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
643                 , deviceTimeNs
644                 , ENUM_EXTRACT(encodingForStats)
645                 , frameCount
646                 , intervalCount
647                 , sampleRate
648                 , ENUM_EXTRACT(flagsForStats)
649                 , underrun
650                 , ENUM_EXTRACT(typeForStats)
651             );
652             ALOGV("%s: statsd %s", __func__, str.c_str());
653             mAudioAnalytics.mStatsdLog->log(
654                     android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
655         }
656     } break;
657     case TRACK: {
658         std::string callerName;
659         const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
660                 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
661 
662         std::string contentType;
663         mAudioAnalytics.mAnalyticsState->timeMachine().get(
664                 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
665         double deviceLatencyMs = 0.;
666         mAudioAnalytics.mAnalyticsState->timeMachine().get(
667                 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
668         double deviceStartupMs = 0.;
669         mAudioAnalytics.mAnalyticsState->timeMachine().get(
670                 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
671         double deviceVolume = 0.;
672         mAudioAnalytics.mAnalyticsState->timeMachine().get(
673                 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
674         std::string packageName;
675         int64_t versionCode = 0;
676         int32_t uid = -1;
677         mAudioAnalytics.mAnalyticsState->timeMachine().get(
678                 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
679         if (uid != -1) {
680             std::tie(packageName, versionCode) =
681                     MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
682         }
683         double playbackPitch = 0.;
684         mAudioAnalytics.mAnalyticsState->timeMachine().get(
685                 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
686         double playbackSpeed = 0.;
687         mAudioAnalytics.mAnalyticsState->timeMachine().get(
688                 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
689         int32_t selectedDeviceId = 0;
690         mAudioAnalytics.mAnalyticsState->timeMachine().get(
691                 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
692         std::string streamType;
693         mAudioAnalytics.mAnalyticsState->timeMachine().get(
694                 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
695         std::string traits;
696         mAudioAnalytics.mAnalyticsState->timeMachine().get(
697                 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
698         int32_t underrun = 0;
699         mAudioAnalytics.mAnalyticsState->timeMachine().get(
700                 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
701         std::string usage;
702         mAudioAnalytics.mAnalyticsState->timeMachine().get(
703                 key, AMEDIAMETRICS_PROP_USAGE, &usage);
704         // Android S
705         std::string logSessionId;
706         mAudioAnalytics.mAnalyticsState->timeMachine().get(
707                 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
708 
709         const auto callerNameForStats =
710                 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
711         const auto contentTypeForStats =
712                 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
713         const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
714         const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
715         const auto streamTypeForStats =
716                 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
717         const auto traitsForStats =
718                  types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
719         const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
720         // Android S
721         const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
722 
723         LOG(LOG_LEVEL) << "key:" << key
724               << " id:" << id
725               << " outputDevices:" << outputDevices << "(" << outputDeviceBits
726               << ") outputDeviceNames:" << outputDeviceNames
727               << " deviceTimeNs:" << deviceTimeNs
728               << " encoding:" << encoding << "(" << encodingForStats
729               << ") frameCount:" << frameCount
730               << " intervalCount:" << intervalCount
731               << " sampleRate:" << sampleRate
732               << " underrun:" << underrun
733               << " flags:" << flags << "(" << flagsForStats
734               << ") callerName:" << callerName << "(" << callerNameForStats
735               << ") contentType:" << contentType << "(" << contentTypeForStats
736               << ") deviceLatencyMs:" << deviceLatencyMs
737               << " deviceStartupMs:" << deviceStartupMs
738               << " deviceVolume:" << deviceVolume
739               << " packageName:" << packageName
740               << " playbackPitch:" << playbackPitch
741               << " playbackSpeed:" << playbackSpeed
742               << " selectedDeviceId:" << selectedDeviceId
743               << " streamType:" << streamType << "(" << streamTypeForStats
744               << ") traits:" << traits << "(" << traitsForStats
745               << ") usage:" << usage << "(" << usageForStats
746               << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
747               << ")";
748         if (clientCalled // only log if client app called AudioTracks
749                 && mAudioAnalytics.mDeliverStatistics) {
750             const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
751                     CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
752                     , ENUM_EXTRACT(outputDeviceBits)
753                     , outputDeviceNames.c_str()
754                     , deviceTimeNs
755                     , ENUM_EXTRACT(encodingForStats)
756                     , frameCount
757                     , intervalCount
758                     , sampleRate
759                     , ENUM_EXTRACT(flagsForStats)
760                     , underrun
761                     , packageName.c_str()
762                     , (float)deviceLatencyMs
763                     , (float)deviceStartupMs
764                     , (float)deviceVolume
765                     , selectedDeviceId
766                     , ENUM_EXTRACT(streamTypeForStats)
767                     , ENUM_EXTRACT(usageForStats)
768                     , ENUM_EXTRACT(contentTypeForStats)
769                     , ENUM_EXTRACT(callerNameForStats)
770                     , ENUM_EXTRACT(traitsForStats)
771                     , logSessionIdForStats.c_str()
772                     );
773             ALOGV("%s: statsd %s", __func__, str.c_str());
774             mAudioAnalytics.mStatsdLog->log(
775                     android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
776         }
777         } break;
778     }
779 
780     // Report this as needed.
781     if (isBluetooth) {
782         // report this for Bluetooth
783     }
784 }
785 
786 // DeviceConnection helper class.
a2dpConnected(const std::shared_ptr<const android::mediametrics::Item> & item)787 void AudioAnalytics::DeviceConnection::a2dpConnected(
788        const std::shared_ptr<const android::mediametrics::Item> &item) {
789     const std::string& key = item->getKey();
790     const int64_t atNs = item->getTimestamp();
791     {
792         std::lock_guard l(mLock);
793         mA2dpConnectionServiceNs = atNs;
794         ++mA2dpConnectionServices;
795 
796         if (mA2dpConnectionRequestNs == 0) {
797             mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
798         }
799         // This sets the time we were connected.  Now we look for the delta in the future.
800     }
801     std::string name;
802     item->get(AMEDIAMETRICS_PROP_NAME, &name);
803     ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
804             key.c_str(), name.c_str(), (long long)atNs);
805 }
806 
createPatch(const std::shared_ptr<const android::mediametrics::Item> & item)807 void AudioAnalytics::DeviceConnection::createPatch(
808        const std::shared_ptr<const android::mediametrics::Item> &item) {
809     std::lock_guard l(mLock);
810     if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
811     const std::string& key = item->getKey();
812     std::string outputDevices;
813     item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
814     if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
815         // TODO compare address
816         int64_t timeDiffNs = item->getTimestamp();
817         if (mA2dpConnectionRequestNs == 0) {
818             ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
819             timeDiffNs -= mA2dpConnectionServiceNs;
820         } else {
821             timeDiffNs -= mA2dpConnectionRequestNs;
822         }
823 
824         mA2dpConnectionRequestNs = 0;
825         mA2dpConnectionServiceNs = 0;
826         ++mA2dpConnectionSuccesses;
827 
828         const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
829 
830         const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
831                 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
832 
833         LOG(LOG_LEVEL) << "key:" << key
834                 << " A2DP SUCCESS"
835                 << " outputDevices:" << outputDeviceBits
836                 << " deviceName:" << mA2dpDeviceName
837                 << " connectionTimeMs:" <<  connectionTimeMs;
838         if (mAudioAnalytics.mDeliverStatistics) {
839             const long_enum_type_t inputDeviceBits{};
840 
841             const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
842                     CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
843                     , ENUM_EXTRACT(inputDeviceBits)
844                     , ENUM_EXTRACT(outputDeviceBits)
845                     , mA2dpDeviceName.c_str()
846                     , types::DEVICE_CONNECTION_RESULT_SUCCESS
847                     , connectionTimeMs
848                     , /* connection_count */ 1
849                     );
850             ALOGV("%s: statsd %s", __func__, str.c_str());
851             mAudioAnalytics.mStatsdLog->log(
852                     android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
853         }
854     }
855 }
856 
857 // Called through AudioManager when the BT service wants to enable
postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(const std::shared_ptr<const android::mediametrics::Item> & item)858 void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
859         const std::shared_ptr<const android::mediametrics::Item> &item) {
860     const int64_t atNs = item->getTimestamp();
861     const std::string& key = item->getKey();
862     std::string state;
863     item->get(AMEDIAMETRICS_PROP_STATE, &state);
864     if (state != "connected") return;
865 
866     std::string name;
867     item->get(AMEDIAMETRICS_PROP_NAME, &name);
868     {
869         std::lock_guard l(mLock);
870         mA2dpConnectionRequestNs = atNs;
871         ++mA2dpConnectionRequests;
872         mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
873     }
874     ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
875             key.c_str(), name.c_str(), (long long)atNs);
876     // TODO: attempt to cancel a timed event, rather than let it expire.
877     mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
878 }
879 
expire()880 void AudioAnalytics::DeviceConnection::expire() {
881     std::lock_guard l(mLock);
882     if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
883 
884     const long_enum_type_t inputDeviceBits{};
885     const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
886             "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
887 
888     if (mA2dpConnectionServiceNs == 0) {
889         ++mA2dpConnectionJavaServiceCancels;  // service did not connect to A2DP
890 
891         LOG(LOG_LEVEL) << "A2DP CANCEL"
892                 << " outputDevices:" << outputDeviceBits
893                 << " deviceName:" << mA2dpDeviceName;
894         if (mAudioAnalytics.mDeliverStatistics) {
895             const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
896                     CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
897                     , ENUM_EXTRACT(inputDeviceBits)
898                     , ENUM_EXTRACT(outputDeviceBits)
899                     , mA2dpDeviceName.c_str()
900                     , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
901                     , /* connection_time_ms */ 0.f
902                     , /* connection_count */ 1
903                     );
904             ALOGV("%s: statsd %s", __func__, str.c_str());
905             mAudioAnalytics.mStatsdLog->log(
906                     android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
907         }
908         return;
909     }
910 
911     // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
912     // Should we check elsewhere?
913     // TODO: disambiguate this case.
914     mA2dpConnectionRequestNs = 0;
915     mA2dpConnectionServiceNs = 0;
916     ++mA2dpConnectionUnknowns;  // connection result unknown
917 
918     LOG(LOG_LEVEL) << "A2DP UNKNOWN"
919             << " outputDevices:" << outputDeviceBits
920             << " deviceName:" << mA2dpDeviceName;
921     if (mAudioAnalytics.mDeliverStatistics) {
922         const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
923                 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
924                 , ENUM_EXTRACT(inputDeviceBits)
925                 , ENUM_EXTRACT(outputDeviceBits)
926                 , mA2dpDeviceName.c_str()
927                 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
928                 , /* connection_time_ms */ 0.f
929                 , /* connection_count */ 1
930                 );
931         ALOGV("%s: statsd %s", __func__, str.c_str());
932         mAudioAnalytics.mStatsdLog->log(
933                 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
934     }
935 }
936 
endAAudioStream(const std::shared_ptr<const android::mediametrics::Item> & item,CallerPath path) const937 void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
938         const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
939     const std::string& key = item->getKey();
940 
941     std::string directionStr;
942     mAudioAnalytics.mAnalyticsState->timeMachine().get(
943             key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
944     const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
945 
946     int32_t framesPerBurst = -1;
947     mAudioAnalytics.mAnalyticsState->timeMachine().get(
948             key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
949 
950     int32_t bufferSizeInFrames = -1;
951     mAudioAnalytics.mAnalyticsState->timeMachine().get(
952             key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
953 
954     int32_t bufferCapacityInFrames = -1;
955     mAudioAnalytics.mAnalyticsState->timeMachine().get(
956             key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
957 
958     int32_t channelCount = -1;
959     mAudioAnalytics.mAnalyticsState->timeMachine().get(
960             key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
961     if (channelCount == -1) {
962         // Try to get channel count from channel mask. From the legacy path,
963         // only channel mask are logged.
964         int32_t channelMask = 0;
965         mAudioAnalytics.mAnalyticsState->timeMachine().get(
966                 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
967         if (channelMask != 0) {
968             switch (direction) {
969                 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
970                     channelCount = audio_channel_count_from_out_mask(channelMask);
971                     break;
972                 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
973                     channelCount = audio_channel_count_from_in_mask(channelMask);
974                     break;
975                 default:
976                     ALOGW("Invalid direction %d", direction);
977             }
978         }
979     }
980 
981     int64_t totalFramesTransferred = -1;
982     mAudioAnalytics.mAnalyticsState->timeMachine().get(
983             key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
984 
985     std::string perfModeRequestedStr;
986     mAudioAnalytics.mAnalyticsState->timeMachine().get(
987             key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
988     const auto perfModeRequested =
989             types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
990 
991     std::string perfModeActualStr;
992     mAudioAnalytics.mAnalyticsState->timeMachine().get(
993             key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
994     const auto perfModeActual =
995             types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
996 
997     std::string sharingModeActualStr;
998     mAudioAnalytics.mAnalyticsState->timeMachine().get(
999             key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1000     const auto sharingModeActual =
1001             types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
1002 
1003     int32_t xrunCount = -1;
1004     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1005             key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1006 
1007     std::string serializedDeviceTypes;
1008     // TODO: only routed device id is logged, but no device type
1009 
1010     std::string formatAppStr;
1011     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1012             key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
1013     const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
1014 
1015     std::string formatDeviceStr;
1016     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1017             key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1018     const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1019 
1020     std::string logSessionId;
1021     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1022             key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
1023 
1024     int32_t sampleRate = 0;
1025     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1026             key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1027 
1028     std::string contentTypeStr;
1029     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1030             key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1031     const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1032 
1033     std::string sharingModeRequestedStr;
1034     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1035             key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1036     const auto sharingModeRequested =
1037             types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1038 
1039     LOG(LOG_LEVEL) << "key:" << key
1040             << " path:" << path
1041             << " direction:" << direction << "(" << directionStr << ")"
1042             << " frames_per_burst:" << framesPerBurst
1043             << " buffer_size:" << bufferSizeInFrames
1044             << " buffer_capacity:" << bufferCapacityInFrames
1045             << " channel_count:" << channelCount
1046             << " total_frames_transferred:" << totalFramesTransferred
1047             << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
1048             << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
1049             << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
1050             << " xrun_count:" << xrunCount
1051             << " device_type:" << serializedDeviceTypes
1052             << " format_app:" << formatApp << "(" << formatAppStr << ")"
1053             << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
1054             << " log_session_id: " << logSessionId
1055             << " sample_rate: " << sampleRate
1056             << " content_type: " << contentType << "(" << contentTypeStr << ")"
1057             << " sharing_requested:" << sharingModeRequested
1058                     << "(" << sharingModeRequestedStr << ")";
1059 
1060     if (mAudioAnalytics.mDeliverStatistics) {
1061         android::util::BytesField bf_serialized(
1062             serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1063         const auto result = sendToStatsd(
1064                 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
1065                 , path
1066                 , direction
1067                 , framesPerBurst
1068                 , bufferSizeInFrames
1069                 , bufferCapacityInFrames
1070                 , channelCount
1071                 , totalFramesTransferred
1072                 , perfModeRequested
1073                 , perfModeActual
1074                 , sharingModeActual
1075                 , xrunCount
1076                 , bf_serialized
1077                 , formatApp
1078                 , formatDevice
1079                 , logSessionId.c_str()
1080                 , sampleRate
1081                 , contentType
1082                 , sharingModeRequested
1083                 );
1084         std::stringstream ss;
1085         ss << "result:" << result;
1086         const auto fieldsStr = printFields(AAudioStreamFields,
1087                 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
1088                 , path
1089                 , direction
1090                 , framesPerBurst
1091                 , bufferSizeInFrames
1092                 , bufferCapacityInFrames
1093                 , channelCount
1094                 , totalFramesTransferred
1095                 , perfModeRequested
1096                 , perfModeActual
1097                 , sharingModeActual
1098                 , xrunCount
1099                 , serializedDeviceTypes.c_str()
1100                 , formatApp
1101                 , formatDevice
1102                 , logSessionId.c_str()
1103                 , sampleRate
1104                 , contentType
1105                 , sharingModeRequested
1106                 );
1107         ss << " " << fieldsStr;
1108         std::string str = ss.str();
1109         ALOGV("%s: statsd %s", __func__, str.c_str());
1110         mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
1111     }
1112 }
1113 
1114 } // namespace android::mediametrics
1115