• 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 <aaudio/AAudio.h>        // error codes
25 #include <audio_utils/clock.h>    // clock conversions
26 #include <cutils/properties.h>
27 #include <stats_media_metrics.h>             // statsd
28 #include <system/audio.h>
29 
30 #include "AudioTypes.h"           // string to int conversions
31 #include "MediaMetricsService.h"  // package info
32 #include "StringUtils.h"
33 #include "ValidateId.h"
34 
35 #define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
36 
37 namespace android::mediametrics {
38 
39 // Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
40 #define STATSD_ENABLE
41 
42 #ifdef STATSD_ENABLE
43 #define CONDITION(INT_VALUE) (INT_VALUE)  // allow value
44 #else
45 #define CONDITION(INT_VALUE) (int(0))     // mask value since the proto may not be defined yet.
46 #endif
47 
48 // Maximum length of a device name.
49 // static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
50 
51 // Transmit Enums to statsd in integer or strings  (this must match the atoms.proto)
52 static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
53 
54 // derive types based on integer or strings.
55 using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
56 using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
57 
58 // Convert std::string to char *
59 template <typename T>
ENUM_EXTRACT(const T & x)60 auto ENUM_EXTRACT(const T& x) {
61     if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
62         return x.c_str();
63     } else {
64         return x;
65     }
66 }
67 
68 // The status variable contains status_t codes which are used by
69 // the core audio framework. We also consider AAudio status codes.
70 //
71 // Compare with mediametrics::statusToStatusString
72 //
extendedStatusToStatusString(status_t status)73 inline constexpr const char* extendedStatusToStatusString(status_t status) {
74     switch (status) {
75     case BAD_VALUE:           // status_t
76     case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
77     case AAUDIO_ERROR_INVALID_FORMAT:
78     case AAUDIO_ERROR_INVALID_RATE:
79     case AAUDIO_ERROR_NULL:
80     case AAUDIO_ERROR_OUT_OF_RANGE:
81         return AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT;
82     case DEAD_OBJECT:         // status_t
83     case FAILED_TRANSACTION:  // status_t
84     case AAUDIO_ERROR_DISCONNECTED:
85     case AAUDIO_ERROR_INVALID_HANDLE:
86     case AAUDIO_ERROR_NO_SERVICE:
87         return AMEDIAMETRICS_PROP_STATUS_VALUE_IO;
88     case NO_MEMORY:           // status_t
89     case AAUDIO_ERROR_NO_FREE_HANDLES:
90     case AAUDIO_ERROR_NO_MEMORY:
91         return AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY;
92     case PERMISSION_DENIED:   // status_t
93         return AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY;
94     case INVALID_OPERATION:   // status_t
95     case NO_INIT:             // status_t
96     case AAUDIO_ERROR_INVALID_STATE:
97     case AAUDIO_ERROR_UNAVAILABLE:
98     case AAUDIO_ERROR_UNIMPLEMENTED:
99         return AMEDIAMETRICS_PROP_STATUS_VALUE_STATE;
100     case WOULD_BLOCK:         // status_t
101     case AAUDIO_ERROR_TIMEOUT:
102     case AAUDIO_ERROR_WOULD_BLOCK:
103         return AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT;
104     default:
105         if (status >= 0) return AMEDIAMETRICS_PROP_STATUS_VALUE_OK; // non-negative values "OK"
106         [[fallthrough]];            // negative values are error.
107     case UNKNOWN_ERROR:       // status_t
108         return AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN;
109     }
110 }
111 
112 static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
113 
114 static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
115 
116 static constexpr const char * SUPPRESSED = "SUPPRESSED";
117 
118 /*
119  * For logging purposes, we list all of the MediaMetrics atom fields,
120  * which can then be associated with consecutive arguments to the statsd write.
121  */
122 
123 static constexpr const char * const AudioRecordDeviceUsageFields[] = {
124     "mediametrics_audiorecorddeviceusage_reported", // proto number
125     "devices",
126     "device_names",
127     "device_time_nanos",
128     "encoding",
129     "frame_count",
130     "interval_count",
131     "sample_rate",
132     "flags",
133     "package_name",
134     "selected_device_id",
135     "caller",
136     "source",
137     "log_session_id",
138 };
139 
140 static constexpr const char * const AudioThreadDeviceUsageFields[] = {
141     "mediametrics_audiothreaddeviceusage_reported",
142     "devices",
143     "device_names",
144     "device_time_nanos",
145     "encoding",
146     "frame_count",
147     "interval_count",
148     "sample_rate",
149     "flags",
150     "xruns",
151     "type",
152 };
153 
154 static constexpr const char * const AudioTrackDeviceUsageFields[] = {
155     "mediametrics_audiotrackdeviceusage_reported",
156     "devices",
157     "device_names",
158     "device_time_nanos",
159     "encoding",
160     "frame_count",
161     "interval_count",
162     "sample_rate",
163     "flags",
164     "xruns",
165     "package_name",
166     "device_latency_millis",
167     "device_startup_millis",
168     "device_volume",
169     "selected_device_id",
170     "stream_type",
171     "usage",
172     "content_type",
173     "caller",
174     "traits",
175     "log_session_id",
176 };
177 
178 static constexpr const char * const AudioRecordStatusFields[] {
179     "mediametrics_audiorecordstatus_reported",
180     "status",
181     "debug_message",
182     "status_subcode",
183     "uid",
184     "event",
185     "input_flags",
186     "source",
187     "encoding",
188     "channel_mask",
189     "buffer_frame_count",
190     "sample_rate",
191 };
192 
193 static constexpr const char * const AudioTrackStatusFields[] {
194     "mediametrics_audiotrackstatus_reported",
195     "status",
196     "debug_message",
197     "status_subcode",
198     "uid",
199     "event",
200     "output_flags",
201     "content_type",
202     "usage",
203     "encoding",
204     "channel_mask",
205     "buffer_frame_count",
206     "sample_rate",
207     "speed",
208     "pitch",
209 };
210 
211 static constexpr const char * const AudioDeviceConnectionFields[] = {
212     "mediametrics_audiodeviceconnection_reported",
213     "input_devices",
214     "output_devices",
215     "device_names",
216     "result",
217     "time_to_connect_millis",
218     "connection_count",
219 };
220 
221 static constexpr const char * const AAudioStreamFields[] {
222     "mediametrics_aaudiostream_reported",
223     "path",
224     "direction",
225     "frames_per_burst",
226     "buffer_size",
227     "buffer_capacity",
228     "channel_count",
229     "total_frames_transferred",
230     "perf_mode_requested",
231     "perf_mode_actual",
232     "sharing",
233     "xrun_count",
234     "device_type",
235     "format_app",
236     "format_device",
237     "log_session_id",
238     "sample_rate",
239     "content_type",
240     "sharing_requested",
241     "format_hardware",
242     "channel_count_hardware",
243     "sample_rate_hardware",
244     "uid",
245 };
246 
247 static constexpr const char * HeadTrackerDeviceEnabledFields[] {
248     "mediametrics_headtrackerdeviceenabled_reported",
249     "type",
250     "event",
251     "enabled",
252 };
253 
254 static constexpr const char * HeadTrackerDeviceSupportedFields[] {
255     "mediametrics_headtrackerdevicesupported_reported",
256     "type",
257     "event",
258     "supported",
259 };
260 
261 static constexpr const char * SpatializerCapabilitiesFields[] {
262     "mediametrics_spatializer_reported",
263     "head_tracking_modes",
264     "spatializer_levels",
265     "spatializer_modes",
266     "channel_masks",
267 };
268 
269 static constexpr const char * SpatializerDeviceEnabledFields[] {
270     "mediametrics_spatializerdeviceenabled_reported",
271     "type",
272     "event",
273     "enabled",
274 };
275 
276 static constexpr const char * const MidiDeviceCloseFields[] {
277     "mediametrics_midi_device_close_reported",
278     "uid",
279     "midi_device_id",
280     "input_port_count",
281     "output_port_count",
282     "device_type",
283     "is_shared",
284     "supports_ump",
285     "using_alsa",
286     "duration_ns",
287     "opened_count",
288     "closed_count",
289     "device_disconnected",
290     "total_input_bytes",
291     "total_output_bytes",
292 };
293 
294 /**
295  * printFields is a helper method that prints the fields and corresponding values
296  * in a human readable style.
297  */
298 template <size_t N, typename ...Types>
printFields(const char * const (& fields)[N],Types...args)299 std::string printFields(const char * const (& fields)[N], Types ... args)
300 {
301     std::stringstream ss;
302     ss << " { ";
303     stringutils::fieldPrint(ss, fields, args...);
304     ss << "}";
305     return ss.str();
306 }
307 
308 /**
309  * sendToStatsd is a helper method that sends the arguments to statsd
310  */
311 template <typename ...Types>
sendToStatsd(Types...args)312 int sendToStatsd(Types ... args)
313 {
314     int result = 0;
315 
316 #ifdef STATSD_ENABLE
317     result = stats::media_metrics::stats_write(args...);
318 #endif
319     return result;
320 }
321 
322 /**
323  * sendToStatsd is a helper method that sends the arguments to statsd
324  * and returns a pair { result, summary_string }.
325  */
326 template <size_t N, typename ...Types>
sendToStatsd(const char * const (& fields)[N],Types...args)327 std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
328 {
329     int result = 0;
330     std::stringstream ss;
331 
332 #ifdef STATSD_ENABLE
333     result = stats::media_metrics::stats_write(args...);
334     ss << "result:" << result;
335 #endif
336     ss << " { ";
337     stringutils::fieldPrint(ss, fields, args...);
338     ss << "}";
339     return { result, ss.str() };
340 }
341 
AudioAnalytics(const std::shared_ptr<StatsdLog> & statsdLog)342 AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
343     : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
344     , mStatsdLog(statsdLog)
345     , mAudioPowerUsage(this, statsdLog)
346 {
347     SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
348     ALOGD("%s", __func__);
349 
350     // Add action to save AnalyticsState if audioserver is restarted.
351     // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
352     // as well as TimeCheck events.
353     mActions.addAction(
354         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
355         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
356         std::make_shared<AnalyticsActions::Function>(
357             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
358                 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
359             }));
360     mActions.addAction(
361         AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
362         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
363         std::make_shared<AnalyticsActions::Function>(
364             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
365                 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
366             }));
367     mActions.addAction(
368         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
369         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
370         std::make_shared<AnalyticsActions::Function>(
371             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
372                 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
373             }));
374     mActions.addAction(
375         AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
376         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
377         std::make_shared<AnalyticsActions::Function>(
378             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
379                 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
380             }));
381 
382     // Handle legacy aaudio playback stream statistics
383     mActions.addAction(
384         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
385         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
386         std::make_shared<AnalyticsActions::Function>(
387             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
388                 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
389             }));
390 
391     // Handle legacy aaudio capture stream statistics
392     mActions.addAction(
393         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
394         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
395         std::make_shared<AnalyticsActions::Function>(
396             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
397                 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
398             }));
399 
400     // Handle mmap aaudio stream statistics
401     mActions.addAction(
402         AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
403         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
404         std::make_shared<AnalyticsActions::Function>(
405             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
406                 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
407             }));
408 
409     // Handle device use record statistics
410     mActions.addAction(
411         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
412         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
413         std::make_shared<AnalyticsActions::Function>(
414             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
415                 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
416             }));
417 
418     // Handle device use thread statistics
419     mActions.addAction(
420         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
421         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
422         std::make_shared<AnalyticsActions::Function>(
423             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
424                 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
425             }));
426 
427     // Handle device use track statistics
428     mActions.addAction(
429         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
430         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
431         std::make_shared<AnalyticsActions::Function>(
432             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
433                 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
434             }));
435 
436 
437     // Handle device connection statistics
438 
439     // We track connections (not disconnections) for the time to connect.
440     // TODO: consider BT requests in their A2dp service
441     // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
442     // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
443     // AudioDeviceBroker.postA2dpActiveDeviceChange
444     mActions.addAction(
445         "audio.device.a2dp.state",
446         "connected",
447         std::make_shared<AnalyticsActions::Function>(
448             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
449                 mDeviceConnection.a2dpConnected(item);
450             }));
451     // If audio is active, we expect to see a createAudioPatch after the device is connected.
452     mActions.addAction(
453         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
454         std::string("createAudioPatch"),
455         std::make_shared<AnalyticsActions::Function>(
456             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
457                 mDeviceConnection.createPatch(item);
458             }));
459 
460     // Called from BT service
461     mActions.addAction(
462         AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
463         "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
464         "." AMEDIAMETRICS_PROP_STATE,
465         "connected",
466         std::make_shared<AnalyticsActions::Function>(
467             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
468                 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
469             }));
470 
471     // Handle power usage
472     mActions.addAction(
473         AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
474         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
475         std::make_shared<AnalyticsActions::Function>(
476             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
477                 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
478             }));
479 
480     mActions.addAction(
481         AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
482         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
483         std::make_shared<AnalyticsActions::Function>(
484             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
485                 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
486             }));
487 
488     mActions.addAction(
489         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
490         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
491         std::make_shared<AnalyticsActions::Function>(
492             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
493                 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
494                 mAudioPowerUsage.checkMode(item);
495             }));
496 
497     mActions.addAction(
498         AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
499         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
500         std::make_shared<AnalyticsActions::Function>(
501             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
502                 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
503                 mAudioPowerUsage.checkVoiceVolume(item);
504             }));
505 
506     mActions.addAction(
507         AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
508         std::string("createAudioPatch"),
509         std::make_shared<AnalyticsActions::Function>(
510             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
511                 mAudioPowerUsage.checkCreatePatch(item);
512             }));
513 
514     // Handle Spatializer - these keys are prefixed by "audio.spatializer."
515     mActions.addAction(
516         AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
517         std::monostate{}, /* match any event */
518         std::make_shared<AnalyticsActions::Function>(
519             [this](const std::shared_ptr<const android::mediametrics::Item> &item){
520                 mSpatializer.onEvent(item);
521             }));
522 
523     // Handle MIDI
524     mActions.addAction(
525         AMEDIAMETRICS_KEY_AUDIO_MIDI "." AMEDIAMETRICS_PROP_EVENT,
526         std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED),
527         std::make_shared<AnalyticsActions::Function>(
528             [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
529                 mMidiLogging.onEvent(item);
530             }));
531 }
532 
~AudioAnalytics()533 AudioAnalytics::~AudioAnalytics()
534 {
535     ALOGD("%s", __func__);
536     mTimedAction.quit(); // ensure no deferred access during destructor.
537 }
538 
submit(const std::shared_ptr<const mediametrics::Item> & item,bool isTrusted)539 status_t AudioAnalytics::submit(
540         const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
541 {
542     if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
543     status_t status = mAnalyticsState->submit(item, isTrusted);
544 
545     // Status is selectively authenticated.
546     processStatus(item);
547 
548     if (status != NO_ERROR) return status;  // may not be permitted.
549 
550     // Only if the item was successfully submitted (permission)
551     // do we check triggered actions.
552     processActions(item);
553     return NO_ERROR;
554 }
555 
dump(int32_t lines,int64_t sinceNs,const char * prefix) const556 std::pair<std::string, int32_t> AudioAnalytics::dump(
557         int32_t lines, int64_t sinceNs, const char *prefix) const
558 {
559     std::stringstream ss;
560     int32_t ll = lines;
561 
562     if (ll > 0) {
563         auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
564         ss << s;
565         ll -= l;
566     }
567     if (ll > 0) {
568         ss << "Prior audioserver state:\n";
569         --ll;
570     }
571     if (ll > 0) {
572         auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
573         ss << s;
574         ll -= l;
575     }
576 
577     if (ll > 0 && prefix == nullptr) {
578         auto [s, l] = mAudioPowerUsage.dump(ll);
579         ss << s;
580         ll -= l;
581     }
582 
583     return { ss.str(), lines - ll };
584 }
585 
processActions(const std::shared_ptr<const mediametrics::Item> & item)586 void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
587 {
588     auto actions = mActions.getActionsForItem(item); // internally locked.
589     // Execute actions with no lock held.
590     for (const auto& action : actions) {
591         (*action)(item);
592     }
593 }
594 
processStatus(const std::shared_ptr<const mediametrics::Item> & item)595 void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
596 {
597     int32_t status;
598     if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
599 
600     // Any record with a status will automatically be added to a heat map.
601     // Standard information.
602     const auto key = item->getKey();
603     const auto uid = item->getUid();
604 
605     // from audio.track.10 ->  prefix = audio.track, suffix = 10
606     // from audio.track.error -> prefix = audio.track, suffix = error
607     const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
608 
609     std::string message;
610     item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
611 
612     int32_t subCode = 0; // not used
613     (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
614 
615     std::string eventStr; // optional
616     item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
617 
618     const std::string statusString = extendedStatusToStatusString(status);
619 
620     // Add to the heat map - we automatically track every item's status to see
621     // the types of errors and the frequency of errors.
622     mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
623 
624     // Certain keys/event pairs are sent to statsd.  If we get a match (true) we return early.
625     if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
626     if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
627 }
628 
reportAudioRecordStatus(const std::shared_ptr<const mediametrics::Item> & item,const std::string & key,const std::string & eventStr,const std::string & statusString,uid_t uid,const std::string & message,int32_t subCode) const629 bool AudioAnalytics::reportAudioRecordStatus(
630         const std::shared_ptr<const mediametrics::Item>& item,
631         const std::string& key, const std::string& eventStr,
632         const std::string& statusString, uid_t uid, const std::string& message,
633         int32_t subCode) const
634 {
635     // Note that the prefixes often end with a '.' so we use startsWith.
636     if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
637     if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
638         const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
639 
640         // currently we only send create status events.
641         const int32_t event = stats::media_metrics::
642                 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
643 
644         // The following fields should all be present in a create event.
645         std::string flagsStr;
646         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
647                 "%s: %s missing %s field", __func__,
648                 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
649         const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
650 
651         // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
652 
653         std::string sourceStr;
654         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
655                 "%s: %s missing %s field",
656                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
657         const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
658 
659         // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
660 
661         std::string encodingStr;
662         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
663                 "%s: %s missing %s field",
664                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
665         const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
666 
667         int32_t channelMask = 0;
668         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
669                 "%s: %s missing %s field",
670                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
671         int32_t frameCount = 0;
672         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
673                 "%s: %s missing %s field",
674                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
675         int32_t sampleRate = 0;
676         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
677                 "%s: %s missing %s field",
678                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
679 
680         const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
681                 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
682                 , atom_status
683                 , message.c_str()
684                 , subCode
685                 , uid
686                 , event
687                 , flags
688                 , source
689                 , encoding
690                 , (int64_t)channelMask
691                 , frameCount
692                 , sampleRate
693                 );
694         ALOGV("%s: statsd %s", __func__, str.c_str());
695         mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
696         return true;
697     }
698     return false;
699 }
700 
reportAudioTrackStatus(const std::shared_ptr<const mediametrics::Item> & item,const std::string & key,const std::string & eventStr,const std::string & statusString,uid_t uid,const std::string & message,int32_t subCode) const701 bool AudioAnalytics::reportAudioTrackStatus(
702         const std::shared_ptr<const mediametrics::Item>& item,
703         const std::string& key, const std::string& eventStr,
704         const std::string& statusString, uid_t uid, const std::string& message,
705         int32_t subCode) const
706 {
707     // Note that the prefixes often end with a '.' so we use startsWith.
708     if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
709     if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
710         const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
711 
712         // currently we only send create status events.
713         const int32_t event = stats::media_metrics::
714                 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
715 
716         // The following fields should all be present in a create event.
717         std::string flagsStr;
718         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
719                 "%s: %s missing %s field",
720                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
721         const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
722 
723         // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
724 
725         std::string contentTypeStr;
726         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
727                 "%s: %s missing %s field",
728                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
729         const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
730 
731         std::string usageStr;
732         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
733                 "%s: %s missing %s field",
734                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
735         const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
736 
737         // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
738 
739         std::string encodingStr;
740         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
741                 "%s: %s missing %s field",
742                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
743         const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
744 
745         int32_t channelMask = 0;
746         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
747                 "%s: %s missing %s field",
748                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
749         int32_t frameCount = 0;
750         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
751                 "%s: %s missing %s field",
752                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
753         int32_t sampleRate = 0;
754         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
755                 "%s: %s missing %s field",
756                 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
757         double speed = 0.f;  // default is 1.f
758         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
759                 "%s: %s missing %s field",
760                 __func__,
761                 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
762         double pitch = 0.f;  // default is 1.f
763         ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
764                 "%s: %s missing %s field",
765                 __func__,
766                 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
767         const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
768                 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
769                 , atom_status
770                 , message.c_str()
771                 , subCode
772                 , uid
773                 , event
774                 , flags
775                 , contentType
776                 , usage
777                 , encoding
778                 , (int64_t)channelMask
779                 , frameCount
780                 , sampleRate
781                 , (float)speed
782                 , (float)pitch
783                 );
784         ALOGV("%s: statsd %s", __func__, str.c_str());
785         mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
786         return true;
787     }
788     return false;
789 }
790 
791 // HELPER METHODS
792 
getThreadFromTrack(const std::string & track) const793 std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
794 {
795     int32_t threadId_int32{};
796     if (mAnalyticsState->timeMachine().get(
797             track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
798         return {};
799     }
800     return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
801 }
802 
803 // DeviceUse helper class.
endAudioIntervalGroup(const std::shared_ptr<const android::mediametrics::Item> & item,ItemType itemType) const804 void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
805        const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
806     const std::string& key = item->getKey();
807     const std::string id = key.substr(
808             (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
809             : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
810             : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
811              - 1);
812     // deliver statistics
813     int64_t deviceTimeNs = 0;
814     mAudioAnalytics.mAnalyticsState->timeMachine().get(
815             key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
816     std::string encoding;
817     mAudioAnalytics.mAnalyticsState->timeMachine().get(
818             key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
819     int32_t frameCount = 0;
820     mAudioAnalytics.mAnalyticsState->timeMachine().get(
821             key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
822     int32_t intervalCount = 0;
823     mAudioAnalytics.mAnalyticsState->timeMachine().get(
824             key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
825     int32_t sampleRate = 0;
826     mAudioAnalytics.mAnalyticsState->timeMachine().get(
827             key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
828     std::string flags;
829     mAudioAnalytics.mAnalyticsState->timeMachine().get(
830             key, AMEDIAMETRICS_PROP_FLAGS, &flags);
831 
832     switch (itemType) {
833     case RECORD: {
834         std::string inputDevicePairs;
835         mAudioAnalytics.mAnalyticsState->timeMachine().get(
836                 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
837 
838         const auto [ inputDeviceStatsd, inputDevices ] =
839                 stringutils::parseInputDevicePairs(inputDevicePairs);
840         const std::string inputDeviceNames;  // not filled currently.
841 
842         std::string callerName;
843         const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
844                 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
845 
846         std::string packageName;
847         int64_t versionCode = 0;
848         int32_t uid = -1;
849         mAudioAnalytics.mAnalyticsState->timeMachine().get(
850                 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
851         if (uid != -1) {
852             std::tie(packageName, versionCode) =
853                     MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
854         }
855 
856         int32_t selectedDeviceId = 0;
857         mAudioAnalytics.mAnalyticsState->timeMachine().get(
858                 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
859         std::string source;
860         mAudioAnalytics.mAnalyticsState->timeMachine().get(
861                 key, AMEDIAMETRICS_PROP_SOURCE, &source);
862         // Android S
863         std::string logSessionId;
864         mAudioAnalytics.mAnalyticsState->timeMachine().get(
865                 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
866 
867         const auto callerNameForStats =
868                 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
869         const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
870         const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
871         const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
872         // Android S
873         const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
874 
875         LOG(LOG_LEVEL) << "key:" << key
876               << " id:" << id
877               << " inputDevices:" << inputDevices << "(" << inputDeviceStatsd
878               << ") inputDeviceNames:" << inputDeviceNames
879               << " deviceTimeNs:" << deviceTimeNs
880               << " encoding:" << encoding << "(" << encodingForStats
881               << ") frameCount:" << frameCount
882               << " intervalCount:" << intervalCount
883               << " sampleRate:" << sampleRate
884               << " flags:" << flags << "(" << flagsForStats
885               << ") packageName:" << packageName
886               << " selectedDeviceId:" << selectedDeviceId
887               << " callerName:" << callerName << "(" << callerNameForStats
888               << ") source:" << source << "(" << sourceForStats
889               << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
890               << ")";
891         if (clientCalled  // only log if client app called AudioRecord.
892                 && mAudioAnalytics.mDeliverStatistics) {
893             const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
894                     CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
895                     , ENUM_EXTRACT(inputDeviceStatsd)
896                     , inputDeviceNames.c_str()
897                     , deviceTimeNs
898                     , ENUM_EXTRACT(encodingForStats)
899                     , frameCount
900                     , intervalCount
901                     , sampleRate
902                     , ENUM_EXTRACT(flagsForStats)
903 
904                     , packageName.c_str()
905                     , selectedDeviceId
906                     , ENUM_EXTRACT(callerNameForStats)
907                     , ENUM_EXTRACT(sourceForStats)
908                     , logSessionIdForStats.c_str()
909                     );
910             ALOGV("%s: statsd %s", __func__, str.c_str());
911             mAudioAnalytics.mStatsdLog->log(
912                     stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
913         }
914     } break;
915     case THREAD: {
916         std::string type;
917         mAudioAnalytics.mAnalyticsState->timeMachine().get(
918                 key, AMEDIAMETRICS_PROP_TYPE, &type);
919         int32_t underrun = 0; // zero for record types
920         mAudioAnalytics.mAnalyticsState->timeMachine().get(
921                 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
922 
923         const bool isInput = types::isInputThreadType(type);
924 
925         // get device information
926         std::string devicePairs;
927         std::string deviceStatsd;
928         std::string devices;
929         std::string deviceNames;
930         if (isInput) {
931             // Note we get the "last" device which is the one associated with group.
932             item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_INPUTDEVICES,
933                     &devicePairs);
934             std::tie(deviceStatsd, devices) = stringutils::parseInputDevicePairs(devicePairs);
935         } else {
936             // Note we get the "last" device which is the one associated with group.
937             item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_OUTPUTDEVICES,
938                     &devicePairs);
939             std::tie(deviceStatsd, devices) = stringutils::parseOutputDevicePairs(devicePairs);
940             deviceNames = mAudioAnalytics.getDeviceNamesFromOutputDevices(devices);
941         }
942 
943         const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
944         const auto flagsForStats =
945                 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
946                         : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
947         const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
948 
949          LOG(LOG_LEVEL) << "key:" << key
950               << " id:" << id
951               << " devices:" << devices << "(" << deviceStatsd
952               << ") deviceNames:" << deviceNames
953               << " deviceTimeNs:" << deviceTimeNs
954               << " encoding:" << encoding << "(" << encodingForStats
955               << ") frameCount:" << frameCount
956               << " intervalCount:" << intervalCount
957               << " sampleRate:" << sampleRate
958               << " underrun:" << underrun
959               << " flags:" << flags << "(" << flagsForStats
960               << ") type:" << type << "(" << typeForStats
961               << ")";
962         if (mAudioAnalytics.mDeliverStatistics) {
963             const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
964                 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
965                 , ENUM_EXTRACT(deviceStatsd)
966                 , deviceNames.c_str()
967                 , deviceTimeNs
968                 , ENUM_EXTRACT(encodingForStats)
969                 , frameCount
970                 , intervalCount
971                 , sampleRate
972                 , ENUM_EXTRACT(flagsForStats)
973                 , underrun
974                 , ENUM_EXTRACT(typeForStats)
975             );
976             ALOGV("%s: statsd %s", __func__, str.c_str());
977             mAudioAnalytics.mStatsdLog->log(
978                     stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
979         }
980     } break;
981     case TRACK: {
982         std::string outputDevicePairs;
983         mAudioAnalytics.mAnalyticsState->timeMachine().get(
984                 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
985 
986         const auto [ outputDeviceStatsd, outputDevices ] =
987                 stringutils::parseOutputDevicePairs(outputDevicePairs);
988         const std::string outputDeviceNames =
989                 mAudioAnalytics.getDeviceNamesFromOutputDevices(outputDevices);
990 
991         std::string callerName;
992         const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
993                 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
994 
995         std::string contentType;
996         mAudioAnalytics.mAnalyticsState->timeMachine().get(
997                 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
998         double deviceLatencyMs = 0.;
999         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1000                 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
1001         double deviceStartupMs = 0.;
1002         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1003                 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
1004         double deviceVolume = 0.;
1005         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1006                 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
1007         std::string packageName;
1008         int64_t versionCode = 0;
1009         int32_t uid = -1;
1010         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1011                 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
1012         if (uid != -1) {
1013             std::tie(packageName, versionCode) =
1014                     MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
1015         }
1016         double playbackPitch = 0.;
1017         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1018                 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
1019         double playbackSpeed = 0.;
1020         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1021                 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
1022         int32_t selectedDeviceId = 0;
1023         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1024                 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
1025         std::string streamType;
1026         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1027                 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
1028         std::string traits;
1029         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1030                 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
1031         int32_t underrun = 0;
1032         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1033                 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
1034         std::string usage;
1035         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1036                 key, AMEDIAMETRICS_PROP_USAGE, &usage);
1037         // Android S
1038         std::string logSessionId;
1039         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1040                 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
1041 
1042         const auto callerNameForStats =
1043                 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1044         const auto contentTypeForStats =
1045                 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1046         const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1047         const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1048         const auto streamTypeForStats =
1049                 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
1050         const auto traitsForStats =
1051                  types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
1052         const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
1053         // Android S
1054         const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
1055 
1056         LOG(LOG_LEVEL) << "key:" << key
1057               << " id:" << id
1058               << " outputDevices:" << outputDevices << "(" << outputDeviceStatsd
1059               << ") outputDeviceNames:" << outputDeviceNames
1060               << " deviceTimeNs:" << deviceTimeNs
1061               << " encoding:" << encoding << "(" << encodingForStats
1062               << ") frameCount:" << frameCount
1063               << " intervalCount:" << intervalCount
1064               << " sampleRate:" << sampleRate
1065               << " underrun:" << underrun
1066               << " flags:" << flags << "(" << flagsForStats
1067               << ") callerName:" << callerName << "(" << callerNameForStats
1068               << ") contentType:" << contentType << "(" << contentTypeForStats
1069               << ") deviceLatencyMs:" << deviceLatencyMs
1070               << " deviceStartupMs:" << deviceStartupMs
1071               << " deviceVolume:" << deviceVolume
1072               << " packageName:" << packageName
1073               << " playbackPitch:" << playbackPitch
1074               << " playbackSpeed:" << playbackSpeed
1075               << " selectedDeviceId:" << selectedDeviceId
1076               << " streamType:" << streamType << "(" << streamTypeForStats
1077               << ") traits:" << traits << "(" << traitsForStats
1078               << ") usage:" << usage << "(" << usageForStats
1079               << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
1080               << ")";
1081         if (clientCalled // only log if client app called AudioTracks
1082                 && mAudioAnalytics.mDeliverStatistics) {
1083             const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
1084                     CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
1085                     , ENUM_EXTRACT(outputDeviceStatsd)
1086                     , outputDeviceNames.c_str()
1087                     , deviceTimeNs
1088                     , ENUM_EXTRACT(encodingForStats)
1089                     , frameCount
1090                     , intervalCount
1091                     , sampleRate
1092                     , ENUM_EXTRACT(flagsForStats)
1093                     , underrun
1094                     , packageName.c_str()
1095                     , (float)deviceLatencyMs
1096                     , (float)deviceStartupMs
1097                     , (float)deviceVolume
1098                     , selectedDeviceId
1099                     , ENUM_EXTRACT(streamTypeForStats)
1100                     , ENUM_EXTRACT(usageForStats)
1101                     , ENUM_EXTRACT(contentTypeForStats)
1102                     , ENUM_EXTRACT(callerNameForStats)
1103                     , ENUM_EXTRACT(traitsForStats)
1104                     , logSessionIdForStats.c_str()
1105                     );
1106             ALOGV("%s: statsd %s", __func__, str.c_str());
1107             mAudioAnalytics.mStatsdLog->log(
1108                     stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
1109         }
1110         } break;
1111     }
1112 }
1113 
1114 // DeviceConnection helper class.
a2dpConnected(const std::shared_ptr<const android::mediametrics::Item> & item)1115 void AudioAnalytics::DeviceConnection::a2dpConnected(
1116        const std::shared_ptr<const android::mediametrics::Item> &item) {
1117     const std::string& key = item->getKey();
1118     const int64_t atNs = item->getTimestamp();
1119     {
1120         std::lock_guard l(mLock);
1121         mA2dpConnectionServiceNs = atNs;
1122         ++mA2dpConnectionServices;
1123 
1124         if (mA2dpConnectionRequestNs == 0) {
1125             mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1126         }
1127         // This sets the time we were connected.  Now we look for the delta in the future.
1128     }
1129     std::string name;
1130     item->get(AMEDIAMETRICS_PROP_NAME, &name);
1131     ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1132             key.c_str(), name.c_str(), (long long)atNs);
1133 }
1134 
createPatch(const std::shared_ptr<const android::mediametrics::Item> & item)1135 void AudioAnalytics::DeviceConnection::createPatch(
1136        const std::shared_ptr<const android::mediametrics::Item> &item) {
1137     std::lock_guard l(mLock);
1138     if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
1139     const std::string& key = item->getKey();
1140     std::string outputDevices;
1141     item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
1142     if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
1143         // TODO compare address
1144         int64_t timeDiffNs = item->getTimestamp();
1145         if (mA2dpConnectionRequestNs == 0) {
1146             ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
1147             timeDiffNs -= mA2dpConnectionServiceNs;
1148         } else {
1149             timeDiffNs -= mA2dpConnectionRequestNs;
1150         }
1151 
1152         mA2dpConnectionRequestNs = 0;
1153         mA2dpConnectionServiceNs = 0;
1154         ++mA2dpConnectionSuccesses;
1155 
1156         const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
1157 
1158         const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1159                 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1160 
1161         LOG(LOG_LEVEL) << "key:" << key
1162                 << " A2DP SUCCESS"
1163                 << " outputDevices:" << outputDeviceBits
1164                 << " deviceName:" << mA2dpDeviceName
1165                 << " connectionTimeMs:" <<  connectionTimeMs;
1166         if (mAudioAnalytics.mDeliverStatistics) {
1167             const long_enum_type_t inputDeviceBits{};
1168 
1169             const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1170                     CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
1171                     , ENUM_EXTRACT(inputDeviceBits)
1172                     , ENUM_EXTRACT(outputDeviceBits)
1173                     , mA2dpDeviceName.c_str()
1174                     , types::DEVICE_CONNECTION_RESULT_SUCCESS
1175                     , connectionTimeMs
1176                     , /* connection_count */ 1
1177                     );
1178             ALOGV("%s: statsd %s", __func__, str.c_str());
1179             mAudioAnalytics.mStatsdLog->log(
1180                     stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
1181         }
1182     }
1183 }
1184 
1185 // Called through AudioManager when the BT service wants to enable
postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(const std::shared_ptr<const android::mediametrics::Item> & item)1186 void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1187         const std::shared_ptr<const android::mediametrics::Item> &item) {
1188     const int64_t atNs = item->getTimestamp();
1189     const std::string& key = item->getKey();
1190     std::string state;
1191     item->get(AMEDIAMETRICS_PROP_STATE, &state);
1192     if (state != "connected") return;
1193 
1194     std::string name;
1195     item->get(AMEDIAMETRICS_PROP_NAME, &name);
1196     {
1197         std::lock_guard l(mLock);
1198         mA2dpConnectionRequestNs = atNs;
1199         ++mA2dpConnectionRequests;
1200         mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
1201     }
1202     ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1203             key.c_str(), name.c_str(), (long long)atNs);
1204     // TODO: attempt to cancel a timed event, rather than let it expire.
1205     mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1206 }
1207 
expire()1208 void AudioAnalytics::DeviceConnection::expire() {
1209     std::lock_guard l(mLock);
1210     if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
1211 
1212     const long_enum_type_t inputDeviceBits{};
1213     const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1214             "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1215 
1216     if (mA2dpConnectionServiceNs == 0) {
1217         ++mA2dpConnectionJavaServiceCancels;  // service did not connect to A2DP
1218 
1219         LOG(LOG_LEVEL) << "A2DP CANCEL"
1220                 << " outputDevices:" << outputDeviceBits
1221                 << " deviceName:" << mA2dpDeviceName;
1222         if (mAudioAnalytics.mDeliverStatistics) {
1223             const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1224                     CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
1225                     , ENUM_EXTRACT(inputDeviceBits)
1226                     , ENUM_EXTRACT(outputDeviceBits)
1227                     , mA2dpDeviceName.c_str()
1228                     , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
1229                     , /* connection_time_ms */ 0.f
1230                     , /* connection_count */ 1
1231                     );
1232             ALOGV("%s: statsd %s", __func__, str.c_str());
1233             mAudioAnalytics.mStatsdLog->log(
1234                     stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
1235         }
1236         return;
1237     }
1238 
1239     // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1240     // Should we check elsewhere?
1241     // TODO: disambiguate this case.
1242     mA2dpConnectionRequestNs = 0;
1243     mA2dpConnectionServiceNs = 0;
1244     ++mA2dpConnectionUnknowns;  // connection result unknown
1245 
1246     LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1247             << " outputDevices:" << outputDeviceBits
1248             << " deviceName:" << mA2dpDeviceName;
1249     if (mAudioAnalytics.mDeliverStatistics) {
1250         const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1251                 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
1252                 , ENUM_EXTRACT(inputDeviceBits)
1253                 , ENUM_EXTRACT(outputDeviceBits)
1254                 , mA2dpDeviceName.c_str()
1255                 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
1256                 , /* connection_time_ms */ 0.f
1257                 , /* connection_count */ 1
1258                 );
1259         ALOGV("%s: statsd %s", __func__, str.c_str());
1260         mAudioAnalytics.mStatsdLog->log(
1261                 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
1262     }
1263 }
1264 
endAAudioStream(const std::shared_ptr<const android::mediametrics::Item> & item,CallerPath path) const1265 void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1266         const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1267     const std::string& key = item->getKey();
1268 
1269     std::string directionStr;
1270     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1271             key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1272     const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1273 
1274     int32_t framesPerBurst = -1;
1275     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1276             key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1277 
1278     int32_t bufferSizeInFrames = -1;
1279     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1280             key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1281 
1282     int32_t bufferCapacityInFrames = -1;
1283     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1284             key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1285 
1286     int32_t channelCount = -1;
1287     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1288             key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
1289     if (channelCount == -1) {
1290         // Try to get channel count from channel mask. From the legacy path,
1291         // only channel mask are logged.
1292         int32_t channelMask = 0;
1293         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1294                 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1295         if (channelMask != 0) {
1296             switch (direction) {
1297                 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
1298                     channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
1299                     break;
1300                 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
1301                     channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
1302                     break;
1303                 default:
1304                     ALOGW("Invalid direction %d", direction);
1305             }
1306         }
1307     }
1308 
1309     int64_t totalFramesTransferred = -1;
1310     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1311             key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
1312 
1313     std::string perfModeRequestedStr;
1314     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1315             key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1316     const auto perfModeRequested =
1317             types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1318 
1319     std::string perfModeActualStr;
1320     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1321             key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1322     const auto perfModeActual =
1323             types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
1324 
1325     std::string sharingModeActualStr;
1326     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1327             key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1328     const auto sharingModeActual =
1329             types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
1330 
1331     int32_t xrunCount = -1;
1332     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1333             key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1334 
1335     std::string serializedDeviceTypes;
1336     // TODO: only routed device id is logged, but no device type
1337 
1338     std::string formatAppStr;
1339     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1340             key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
1341     const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
1342 
1343     std::string formatDeviceStr;
1344     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1345             key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1346     const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1347 
1348     std::string logSessionId;
1349     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1350             key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
1351 
1352     int32_t sampleRate = 0;
1353     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1354             key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1355 
1356     std::string contentTypeStr;
1357     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1358             key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1359     const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1360 
1361     std::string sharingModeRequestedStr;
1362     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1363             key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1364     const auto sharingModeRequested =
1365             types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1366 
1367     std::string formatHardwareStr;
1368     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1369             key, AMEDIAMETRICS_PROP_ENCODINGHARDWARE, &formatHardwareStr);
1370     const auto formatHardware = types::lookup<types::ENCODING, int32_t>(formatHardwareStr);
1371 
1372     int32_t channelCountHardware = -1;
1373     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1374             key, AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE, &channelCountHardware);
1375 
1376     int32_t sampleRateHardware = 0;
1377     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1378             key, AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE, &sampleRateHardware);
1379 
1380     const auto uid = item->getUid();
1381 
1382     LOG(LOG_LEVEL) << "key:" << key
1383             << " path:" << path
1384             << " direction:" << direction << "(" << directionStr << ")"
1385             << " frames_per_burst:" << framesPerBurst
1386             << " buffer_size:" << bufferSizeInFrames
1387             << " buffer_capacity:" << bufferCapacityInFrames
1388             << " channel_count:" << channelCount
1389             << " total_frames_transferred:" << totalFramesTransferred
1390             << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
1391             << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
1392             << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
1393             << " xrun_count:" << xrunCount
1394             << " device_type:" << serializedDeviceTypes
1395             << " format_app:" << formatApp << "(" << formatAppStr << ")"
1396             << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
1397             << " log_session_id: " << logSessionId
1398             << " sample_rate: " << sampleRate
1399             << " content_type: " << contentType << "(" << contentTypeStr << ")"
1400             << " sharing_requested:" << sharingModeRequested
1401                     << "(" << sharingModeRequestedStr << ")"
1402             << " format_hardware:" << formatHardware << "(" << formatHardwareStr << ")"
1403             << " channel_count_hardware:" << channelCountHardware
1404             << " sample_rate_hardware: " << sampleRateHardware
1405             << " uid: " << uid;
1406 
1407     if (mAudioAnalytics.mDeliverStatistics) {
1408         const stats::media_metrics::BytesField bf_serialized(
1409             serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1410         const auto result = sendToStatsd(
1411                 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
1412                 , path
1413                 , direction
1414                 , framesPerBurst
1415                 , bufferSizeInFrames
1416                 , bufferCapacityInFrames
1417                 , channelCount
1418                 , totalFramesTransferred
1419                 , perfModeRequested
1420                 , perfModeActual
1421                 , sharingModeActual
1422                 , xrunCount
1423                 , bf_serialized
1424                 , formatApp
1425                 , formatDevice
1426                 , logSessionId.c_str()
1427                 , sampleRate
1428                 , contentType
1429                 , sharingModeRequested
1430                 , formatHardware
1431                 , channelCountHardware
1432                 , sampleRateHardware
1433                 , uid
1434                 );
1435         std::stringstream ss;
1436         ss << "result:" << result;
1437         const auto fieldsStr = printFields(AAudioStreamFields,
1438                 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
1439                 , path
1440                 , direction
1441                 , framesPerBurst
1442                 , bufferSizeInFrames
1443                 , bufferCapacityInFrames
1444                 , channelCount
1445                 , totalFramesTransferred
1446                 , perfModeRequested
1447                 , perfModeActual
1448                 , sharingModeActual
1449                 , xrunCount
1450                 , serializedDeviceTypes.c_str()
1451                 , formatApp
1452                 , formatDevice
1453                 , logSessionId.c_str()
1454                 , sampleRate
1455                 , contentType
1456                 , sharingModeRequested
1457                 , formatHardware
1458                 , channelCountHardware
1459                 , sampleRateHardware
1460                 , uid
1461                 );
1462         ss << " " << fieldsStr;
1463         std::string str = ss.str();
1464         ALOGV("%s: statsd %s", __func__, str.c_str());
1465         mAudioAnalytics.mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
1466     }
1467 }
1468 
1469 // Create new state, typically occurs after an AudioFlinger ctor event.
newState()1470 void AudioAnalytics::newState()
1471 {
1472     mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1473             *mAnalyticsState.get()));
1474     // Note: get returns shared_ptr temp, whose lifetime is extended
1475     // to end of full expression.
1476     mAnalyticsState->clear();  // TODO: filter the analytics state.
1477     // Perhaps report this.
1478 
1479     // Set up a timer to expire the previous audio state to save space.
1480     // Use the transaction log size as a cookie to see if it is the
1481     // same as before.  A benign race is possible where a state is cleared early.
1482     const size_t size = mPreviousAnalyticsState->transactionLog().size();
1483     mTimedAction.postIn(
1484             std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1485         if (mPreviousAnalyticsState->transactionLog().size() == size) {
1486             ALOGD("expiring previous audio state after %d seconds.",
1487                     PREVIOUS_STATE_EXPIRE_SEC);
1488             mPreviousAnalyticsState->clear();  // removes data from the state.
1489         }
1490     });
1491 }
1492 
onAudioServerStart(Module module,const std::shared_ptr<const android::mediametrics::Item> & item)1493 void AudioAnalytics::Health::onAudioServerStart(Module module,
1494         const std::shared_ptr<const android::mediametrics::Item> &item)
1495 {
1496     const auto nowTime = std::chrono::system_clock::now();
1497     if (module == Module::AUDIOFLINGER) {
1498        {
1499             std::lock_guard lg(mLock);
1500             // reset state on AudioFlinger construction.
1501             // AudioPolicy is created after AudioFlinger.
1502             mAudioFlingerCtorTime = nowTime;
1503             mSimpleLog.log("AudioFlinger ctor");
1504         }
1505         mAudioAnalytics.newState();
1506         return;
1507     }
1508     if (module == Module::AUDIOPOLICY) {
1509         // A start event occurs when audioserver
1510         //
1511         // (1) Starts the first time
1512         // (2) Restarts because of the TimeCheck watchdog
1513         // (3) Restarts not because of the TimeCheck watchdog.
1514         int64_t executionTimeNs = 0;
1515         (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1516         const float loadTimeMs = executionTimeNs * 1e-6f;
1517         std::lock_guard lg(mLock);
1518         const int64_t restarts = mStartCount;
1519         if (mStopCount == mStartCount) {
1520             mAudioPolicyCtorTime = nowTime;
1521             ++mStartCount;
1522             if (mStopCount == 0) {
1523                 // (1) First time initialization.
1524                 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1525                         __func__, item->getKey().c_str(), loadTimeMs);
1526                 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1527             } else {
1528                 // (2) Previous failure caught due to TimeCheck.  We know how long restart takes.
1529                 const float restartMs =
1530                         std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1531                                 mAudioFlingerCtorTime - mStopTime).count();
1532                 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1533                         "restarts:%lld restartMs:%f loadTimeMs:%f",
1534                         __func__, item->getKey().c_str(),
1535                         (long long)restarts, restartMs, loadTimeMs);
1536                 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1537                         (long long)restarts, restartMs, loadTimeMs);
1538             }
1539         } else {
1540             // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1541             // However we can estimate the uptime from the delta time from previous ctor.
1542             const float uptimeMs =
1543                     std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1544                             nowTime - mAudioFlingerCtorTime).count();
1545             mStopCount = mStartCount;
1546             mAudioPolicyCtorTime = nowTime;
1547             ++mStartCount;
1548 
1549             ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1550                     "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1551                     __func__, item->getKey().c_str(),
1552                     (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1553             mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1554                     "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1555                     (long long)restarts, uptimeMs, loadTimeMs);
1556         }
1557     }
1558 }
1559 
onAudioServerTimeout(Module module,const std::shared_ptr<const android::mediametrics::Item> & item)1560 void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1561         const std::shared_ptr<const android::mediametrics::Item> &item)
1562 {
1563     std::string moduleName = getModuleName(module);
1564     int64_t methodCode{};
1565     std::string methodName;
1566     (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1567     (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1568 
1569     std::lock_guard lg(mLock);
1570     if (mStopCount >= mStartCount) {
1571         ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1572             "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1573             __func__, item->getKey().c_str(), moduleName.c_str(),
1574             methodName.c_str(), (long long)methodCode,
1575             (long long)mStopCount, (long long)mStartCount);
1576         return;
1577     }
1578 
1579     const int64_t restarts = mStartCount - 1;
1580     ++mStopCount;
1581     mStopTime = std::chrono::system_clock::now();
1582     const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1583             mStopTime - mAudioFlingerCtorTime).count();
1584     ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1585          __func__, item->getKey().c_str(), moduleName.c_str(),
1586          methodName.c_str(), (long long)methodCode,
1587          (long long)restarts, uptimeMs);
1588     mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1589             moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1590             (long long)restarts, uptimeMs);
1591 }
1592 
dump(int32_t lines,const char * prefix) const1593 std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1594         int32_t lines, const char *prefix) const
1595 {
1596     std::lock_guard lg(mLock);
1597     std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1598     size_t n = std::count(s.begin(), s.end(), '\n');
1599     return { s, n };
1600 }
1601 
1602 // Classifies the setting event for statsd (use generated statsd enums.proto constants).
classifySettingEvent(bool isSetAlready,bool withinBoot)1603 static int32_t classifySettingEvent(bool isSetAlready, bool withinBoot) {
1604     if (isSetAlready) {
1605         return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_NORMAL;
1606     }
1607     if (withinBoot) {
1608         return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_BOOT;
1609     }
1610     return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_FIRST;
1611 }
1612 
onEvent(const std::shared_ptr<const android::mediametrics::Item> & item)1613 void AudioAnalytics::Spatializer::onEvent(
1614         const std::shared_ptr<const android::mediametrics::Item> &item)
1615 {
1616     const auto key = item->getKey();
1617 
1618     if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1619 
1620     const std::string suffix =
1621             key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1622 
1623     std::string eventStr; // optional - find the actual event string.
1624     (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1625 
1626     const size_t delim = suffix.find('.'); // note could use split.
1627     if (delim == suffix.npos) {
1628         // on create with suffix == "0" for the first spatializer effect.
1629 
1630         std::string headTrackingModes;
1631         (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1632 
1633         std::string levels;
1634         (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1635 
1636         std::string modes;
1637         (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1638 
1639         std::string channelMasks;
1640         (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASKS, &channelMasks);
1641 
1642         LOG(LOG_LEVEL) << "key:" << key
1643                 << " headTrackingModes:" << headTrackingModes
1644                 << " levels:" << levels
1645                 << " modes:" << modes
1646                 << " channelMasks:" << channelMasks
1647                 ;
1648 
1649         const std::vector<int32_t> headTrackingModesVector =
1650                 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1651         const std::vector<int32_t> levelsVector =
1652                 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1653         const std::vector<int32_t> modesVector =
1654                 types::vectorFromMap(modes, types::getSpatializerModeMap());
1655         const std::vector<int64_t> channelMasksVector =
1656                 types::channelMaskVectorFromString(channelMasks);
1657 
1658         const auto [ result, str ] = sendToStatsd(SpatializerCapabilitiesFields,
1659                 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED)
1660                 , headTrackingModesVector
1661                 , levelsVector
1662                 , modesVector
1663                 , channelMasksVector
1664                 );
1665 
1666         mAudioAnalytics.mStatsdLog->log(
1667                 stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED, str);
1668 
1669         std::lock_guard lg(mLock);
1670         if (mFirstCreateTimeNs == 0) {
1671             // Only update the create time once to prevent audioserver restart
1672             // from looking like a boot.
1673             mFirstCreateTimeNs = item->getTimestamp();
1674         }
1675         mSimpleLog.log("%s suffix: %s item: %s",
1676                 __func__, suffix.c_str(), item->toString().c_str());
1677     } else {
1678         std::string subtype = suffix.substr(0, delim);
1679         if (subtype != "device") return; // not a device.
1680 
1681         const std::string deviceType = suffix.substr(std::size("device.") - 1);
1682 
1683         const int32_t deviceTypeStatsd =
1684                 types::lookup<types::AUDIO_DEVICE_INFO_TYPE, int32_t>(deviceType);
1685 
1686         std::string address;
1687         (void)item->get(AMEDIAMETRICS_PROP_ADDRESS, &address);
1688         std::string enabled;
1689         (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1690         std::string hasHeadTracker;
1691         (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1692         std::string headTrackerEnabled;
1693         (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1694 
1695         std::lock_guard lg(mLock);
1696 
1697         // Validate from our cached state
1698 
1699         // Our deviceKey takes the device type and appends the address if any.
1700         // This distinguishes different wireless devices for the purposes of tracking.
1701         std::string deviceKey(deviceType);
1702         deviceKey.append("_").append(address);
1703         DeviceState& deviceState = mDeviceStateMap[deviceKey];
1704 
1705         // check whether the settings event is within a certain time of spatializer creation.
1706         const bool withinBoot =
1707                 item->getTimestamp() - mFirstCreateTimeNs < kBootDurationThreshold;
1708 
1709         if (!enabled.empty()) {
1710             if (enabled != deviceState.enabled) {
1711                 const int32_t settingEventStatsd =
1712                         classifySettingEvent(!deviceState.enabled.empty(), withinBoot);
1713                 deviceState.enabled = enabled;
1714                 const bool enabledStatsd = enabled == "true";
1715                 const auto [ result, str ] = sendToStatsd(SpatializerDeviceEnabledFields,
1716                         CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED)
1717                         , deviceTypeStatsd
1718                         , settingEventStatsd
1719                         , enabledStatsd
1720                         );
1721                 mAudioAnalytics.mStatsdLog->log(
1722                         stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED, str);
1723             }
1724         }
1725         if (!hasHeadTracker.empty()) {
1726             if (hasHeadTracker != deviceState.hasHeadTracker) {
1727                 const int32_t settingEventStatsd =
1728                         classifySettingEvent(!deviceState.hasHeadTracker.empty(), withinBoot);
1729                 deviceState.hasHeadTracker = hasHeadTracker;
1730                 const bool supportedStatsd = hasHeadTracker == "true";
1731                 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceSupportedFields,
1732                         CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED)
1733                         , deviceTypeStatsd
1734                         , settingEventStatsd
1735                         , supportedStatsd
1736                         );
1737                 mAudioAnalytics.mStatsdLog->log(
1738                         stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED, str);
1739             }
1740         }
1741         if (!headTrackerEnabled.empty()) {
1742             if (headTrackerEnabled != deviceState.headTrackerEnabled) {
1743                 const int32_t settingEventStatsd =
1744                         classifySettingEvent(!deviceState.headTrackerEnabled.empty(), withinBoot);
1745                 deviceState.headTrackerEnabled = headTrackerEnabled;
1746                 const bool enabledStatsd = headTrackerEnabled == "true";
1747                 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceEnabledFields,
1748                         CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED)
1749                         , deviceTypeStatsd
1750                         , settingEventStatsd
1751                         , enabledStatsd
1752                         );
1753                 mAudioAnalytics.mStatsdLog->log(
1754                         stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED, str);
1755             }
1756         }
1757         mSimpleLog.log("%s deviceKey: %s item: %s",
1758                 __func__, deviceKey.c_str(), item->toString().c_str());
1759     }
1760 }
1761 
dump(int32_t lines,const char * prefix) const1762 std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1763         int32_t lines, const char *prefix) const
1764 {
1765     std::lock_guard lg(mLock);
1766     std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1767     size_t n = std::count(s.begin(), s.end(), '\n');
1768     return { s, n };
1769 }
1770 
onEvent(const std::shared_ptr<const android::mediametrics::Item> & item) const1771 void AudioAnalytics::MidiLogging::onEvent(
1772         const std::shared_ptr<const android::mediametrics::Item> &item) const {
1773     const std::string& key = item->getKey();
1774 
1775     const auto uid = item->getUid();
1776 
1777     int32_t deviceId = -1;
1778     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1779             key, AMEDIAMETRICS_PROP_DEVICEID, &deviceId);
1780 
1781     int32_t inputPortCount = -1;
1782     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1783             key, AMEDIAMETRICS_PROP_INPUTPORTCOUNT, &inputPortCount);
1784 
1785     int32_t outputPortCount = -1;
1786     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1787             key, AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT, &outputPortCount);
1788 
1789     int32_t hardwareType = -1;
1790     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1791             key, AMEDIAMETRICS_PROP_HARDWARETYPE, &hardwareType);
1792 
1793     std::string isSharedString;
1794     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1795             key, AMEDIAMETRICS_PROP_ISSHARED, &isSharedString);
1796     const bool isShared = (isSharedString == "true");
1797 
1798     std::string supportsMidiUmpString;
1799     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1800             key, AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP, &supportsMidiUmpString);
1801     const bool supportsMidiUmp = (supportsMidiUmpString == "true");
1802 
1803     std::string usingAlsaString;
1804     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1805             key, AMEDIAMETRICS_PROP_USINGALSA, &usingAlsaString);
1806     const bool usingAlsa = (usingAlsaString == "true");
1807 
1808     int64_t durationNs = -1;
1809     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1810             key, AMEDIAMETRICS_PROP_DURATIONNS, &durationNs);
1811 
1812     int32_t openedCount = -1;
1813     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1814             key, AMEDIAMETRICS_PROP_OPENEDCOUNT, &openedCount);
1815 
1816     int32_t closedCount = -1;
1817     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1818             key, AMEDIAMETRICS_PROP_CLOSEDCOUNT, &closedCount);
1819 
1820     std::string deviceDisconnectedString;
1821     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1822             key, AMEDIAMETRICS_PROP_DEVICEDISCONNECTED, &deviceDisconnectedString);
1823     const bool deviceDisconnected = (deviceDisconnectedString == "true");
1824 
1825     int32_t totalInputBytes = -1;
1826     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1827             key, AMEDIAMETRICS_PROP_TOTALINPUTBYTES, &totalInputBytes);
1828 
1829     int32_t totalOutputBytes = -1;
1830     mAudioAnalytics.mAnalyticsState->timeMachine().get(
1831             key, AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES, &totalOutputBytes);
1832 
1833     LOG(LOG_LEVEL) << "key:" << key
1834             << " uid:" << uid
1835             << " id:" << deviceId
1836             << " input_port_count:" << inputPortCount
1837             << " output_port_count:" << outputPortCount
1838             << " device_type:" << hardwareType
1839             << " is_shared:" << isSharedString
1840             << " supports_ump:" << supportsMidiUmpString
1841             << " using_alsa:" << usingAlsaString
1842             << " duration_opened_ms:" << durationNs
1843             << " opened_count:" << openedCount
1844             << " closed_count:" << closedCount
1845             << " device_disconnected:" << deviceDisconnectedString
1846             << " total_input_bytes:" << totalInputBytes
1847             << " total_output_bytes:" << totalOutputBytes;
1848 
1849     if (mAudioAnalytics.mDeliverStatistics) {
1850         const auto result = sendToStatsd(
1851                 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1852                 , uid
1853                 , deviceId
1854                 , inputPortCount
1855                 , outputPortCount
1856                 , hardwareType
1857                 , isShared
1858                 , supportsMidiUmp
1859                 , usingAlsa
1860                 , durationNs
1861                 , openedCount
1862                 , closedCount
1863                 , deviceDisconnected
1864                 , totalInputBytes
1865                 , totalOutputBytes);
1866         std::stringstream ss;
1867         ss << "result:" << result;
1868         const auto fieldsStr = printFields(MidiDeviceCloseFields,
1869                 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1870                 , uid
1871                 , deviceId
1872                 , inputPortCount
1873                 , outputPortCount
1874                 , hardwareType
1875                 , isShared
1876                 , supportsMidiUmp
1877                 , usingAlsa
1878                 , durationNs
1879                 , openedCount
1880                 , closedCount
1881                 , deviceDisconnected
1882                 , totalInputBytes
1883                 , totalOutputBytes);
1884         ss << " " << fieldsStr;
1885         std::string str = ss.str();
1886         ALOGV("%s: statsd %s", __func__, str.c_str());
1887         mAudioAnalytics.mStatsdLog->log(
1888                 stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED, str);
1889     }
1890 }
1891 
1892 // This method currently suppresses the name.
getDeviceNamesFromOutputDevices(std::string_view devices) const1893 std::string AudioAnalytics::getDeviceNamesFromOutputDevices(std::string_view devices) const {
1894     std::string deviceNames;
1895     if (stringutils::hasBluetoothOutputDevice(devices)) {
1896         deviceNames = SUPPRESSED;
1897 #if 0   // TODO(b/161554630) sanitize name
1898         mAudioAnalytics.mAnalyticsState->timeMachine().get(
1899             "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
1900         // Remove | if present
1901         stringutils::replace(deviceNames, "|", '?');
1902         if (deviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
1903             deviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
1904         }
1905 #endif
1906     }
1907     return deviceNames;
1908 }
1909 
1910 } // namespace android::mediametrics
1911