blob: 948cee11d25428eafbca9f4dd48a1767fa5f43c4 [file] [log] [blame]
Andy Hung06f3aba2019-12-03 16:36:42 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "AudioAnalytics"
Andy Hung1ea842e2020-05-18 10:47:31 -070019#include <android-base/logging.h>
Andy Hung06f3aba2019-12-03 16:36:42 -080020#include <utils/Log.h>
21
22#include "AudioAnalytics.h"
Andy Hung1ea842e2020-05-18 10:47:31 -070023
Andy Hung73dc2f92021-12-07 21:50:04 -080024#include <aaudio/AAudio.h> // error codes
Andy Hungce9b6632020-04-28 20:15:17 -070025#include <audio_utils/clock.h> // clock conversions
Andy Hung1ea842e2020-05-18 10:47:31 -070026#include <cutils/properties.h>
Vova Sharaienkof58455a2022-09-24 01:47:23 +000027#include <stats_media_metrics.h> // statsd
jiabinfbf20302021-07-28 22:15:01 +000028#include <system/audio.h>
Andy Hung06f3aba2019-12-03 16:36:42 -080029
Andy Hung1ea842e2020-05-18 10:47:31 -070030#include "AudioTypes.h" // string to int conversions
31#include "MediaMetricsService.h" // package info
32#include "StringUtils.h"
Andy Hungc9b6f8b2021-07-08 10:17:55 -070033#include "ValidateId.h"
Andy Hung1ea842e2020-05-18 10:47:31 -070034
35#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
36
Andy Hunga629bd12020-06-05 16:03:53 -070037namespace android::mediametrics {
Andy Hung1ea842e2020-05-18 10:47:31 -070038
Andy Hunga629bd12020-06-05 16:03:53 -070039// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
Andy Hunga0a5ad22020-06-12 09:30:34 -070040#define STATSD_ENABLE
Andy Hung1ea842e2020-05-18 10:47:31 -070041
Andy Hunga629bd12020-06-05 16:03:53 -070042#ifdef STATSD_ENABLE
43#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
Andy Hung1ea842e2020-05-18 10:47:31 -070044#else
Andy Hunga629bd12020-06-05 16:03:53 -070045#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
Andy Hung1ea842e2020-05-18 10:47:31 -070046#endif
47
Andy Hunga629bd12020-06-05 16:03:53 -070048// Maximum length of a device name.
Andy Hung3deef2b2020-07-17 12:58:54 -070049// static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
Andy Hung06f3aba2019-12-03 16:36:42 -080050
Andy Hunga629bd12020-06-05 16:03:53 -070051// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
52static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
53
54// derive types based on integer or strings.
55using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
56using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
57
58// Convert std::string to char *
59template <typename T>
60auto 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
Andy Hung73dc2f92021-12-07 21:50:04 -080068// 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//
73inline 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
Andy Hunga629bd12020-06-05 16:03:53 -0700112static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
113
Andy Hungb18f5062020-06-18 23:10:08 -0700114static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
115
Andy Hung3deef2b2020-07-17 12:58:54 -0700116static constexpr const char * SUPPRESSED = "SUPPRESSED";
117
Andy Hunga629bd12020-06-05 16:03:53 -0700118/*
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
123static 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",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800137 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700138};
139
140static 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
154static 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",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800175 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700176};
177
Andy Hung44326582022-01-11 17:27:09 -0800178static 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
Andy Hungb8918b52021-12-14 22:15:40 -0800193static constexpr const char * const AudioTrackStatusFields[] {
194 "mediametrics_audiotrackstatus_reported",
195 "status",
196 "debug_message",
Andy Hungcb40b982022-01-31 20:08:25 -0800197 "status_subcode",
Andy Hungb8918b52021-12-14 22:15:40 -0800198 "uid",
199 "event",
Andy Hungcb40b982022-01-31 20:08:25 -0800200 "output_flags",
Andy Hungb8918b52021-12-14 22:15:40 -0800201 "content_type",
202 "usage",
203 "encoding",
204 "channel_mask",
205 "buffer_frame_count",
206 "sample_rate",
207 "speed",
208 "pitch",
209};
210
Andy Hunga629bd12020-06-05 16:03:53 -0700211static 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
jiabin92c9a522021-02-12 22:37:42 +0000221static constexpr const char * const AAudioStreamFields[] {
222 "mediametrics_aaudiostream_reported",
jiabin92c9a522021-02-12 22:37:42 +0000223 "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",
jiabinc4c331c2021-03-23 17:11:01 +0000238 "sample_rate",
239 "content_type",
jiabinc8da9032021-04-28 20:42:36 +0000240 "sharing_requested",
Robert Wuf49223c2023-01-26 23:07:02 +0000241 "format_hardware",
242 "channel_count_hardware",
243 "sample_rate_hardware",
jiabin92c9a522021-02-12 22:37:42 +0000244};
245
Andy Hung05874e82022-08-17 17:27:32 -0700246static constexpr const char * HeadTrackerDeviceEnabledFields[] {
247 "mediametrics_headtrackerdeviceenabled_reported",
248 "type",
249 "event",
250 "enabled",
251};
252
253static constexpr const char * HeadTrackerDeviceSupportedFields[] {
254 "mediametrics_headtrackerdevicesupported_reported",
255 "type",
256 "event",
257 "supported",
258};
259
260static constexpr const char * SpatializerCapabilitiesFields[] {
261 "mediametrics_spatializer_reported",
262 "head_tracking_modes",
263 "spatializer_levels",
264 "spatializer_modes",
265 "channel_masks",
266};
267
268static constexpr const char * SpatializerDeviceEnabledFields[] {
269 "mediametrics_spatializerdeviceenabled_reported",
270 "type",
271 "event",
272 "enabled",
273};
274
Robert Wu38439732022-11-02 23:16:04 +0000275static constexpr const char * const MidiDeviceCloseFields[] {
276 "mediametrics_midi_device_close_reported",
277 "uid",
278 "midi_device_id",
279 "input_port_count",
280 "output_port_count",
281 "device_type",
282 "is_shared",
283 "supports_ump",
284 "using_alsa",
285 "duration_ns",
286 "opened_count",
287 "closed_count",
288 "device_disconnected",
289 "total_input_bytes",
290 "total_output_bytes",
291};
292
jiabin92c9a522021-02-12 22:37:42 +0000293/**
294 * printFields is a helper method that prints the fields and corresponding values
295 * in a human readable style.
296 */
297template <size_t N, typename ...Types>
298std::string printFields(const char * const (& fields)[N], Types ... args)
299{
300 std::stringstream ss;
301 ss << " { ";
302 stringutils::fieldPrint(ss, fields, args...);
303 ss << "}";
304 return ss.str();
305}
306
307/**
308 * sendToStatsd is a helper method that sends the arguments to statsd
309 */
310template <typename ...Types>
311int sendToStatsd(Types ... args)
312{
313 int result = 0;
314
315#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000316 result = stats::media_metrics::stats_write(args...);
jiabin92c9a522021-02-12 22:37:42 +0000317#endif
318 return result;
319}
jiabin515eb092020-11-18 17:55:52 -0800320
Andy Hunga629bd12020-06-05 16:03:53 -0700321/**
322 * sendToStatsd is a helper method that sends the arguments to statsd
323 * and returns a pair { result, summary_string }.
324 */
325template <size_t N, typename ...Types>
326std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
327{
328 int result = 0;
329 std::stringstream ss;
330
331#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000332 result = stats::media_metrics::stats_write(args...);
Andy Hunga629bd12020-06-05 16:03:53 -0700333 ss << "result:" << result;
334#endif
335 ss << " { ";
336 stringutils::fieldPrint(ss, fields, args...);
337 ss << "}";
338 return { result, ss.str() };
339}
Andy Hung06f3aba2019-12-03 16:36:42 -0800340
Andy Hung5be90c82021-03-30 14:30:20 -0700341AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700342 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700343 , mStatsdLog(statsdLog)
344 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800345{
Andy Hunga629bd12020-06-05 16:03:53 -0700346 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800347 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800348
349 // Add action to save AnalyticsState if audioserver is restarted.
Andy Hungf4eaa462022-03-09 21:53:09 -0800350 // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
351 // as well as TimeCheck events.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800352 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800353 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
354 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800355 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800356 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungf4eaa462022-03-09 21:53:09 -0800357 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
358 }));
359 mActions.addAction(
360 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
361 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
362 std::make_shared<AnalyticsActions::Function>(
363 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
364 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
365 }));
366 mActions.addAction(
367 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
368 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
369 std::make_shared<AnalyticsActions::Function>(
370 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
371 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
372 }));
373 mActions.addAction(
374 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
375 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
376 std::make_shared<AnalyticsActions::Function>(
377 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
378 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
Andy Hungea186fa2020-01-09 18:13:15 -0800379 }));
380
jiabin97247ea2021-04-07 00:33:38 +0000381 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800382 mActions.addAction(
383 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
384 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
385 std::make_shared<AnalyticsActions::Function>(
386 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
387 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
388 }));
389
jiabin97247ea2021-04-07 00:33:38 +0000390 // Handle legacy aaudio capture stream statistics
391 mActions.addAction(
392 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
393 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
394 std::make_shared<AnalyticsActions::Function>(
395 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
396 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
397 }));
398
jiabin515eb092020-11-18 17:55:52 -0800399 // Handle mmap aaudio stream statistics
400 mActions.addAction(
401 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
402 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
403 std::make_shared<AnalyticsActions::Function>(
404 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
405 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
406 }));
407
Andy Hungea840382020-05-05 21:50:17 -0700408 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800409 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700410 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
411 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800412 std::make_shared<AnalyticsActions::Function>(
413 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700414 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800415 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700416
417 // Handle device use thread statistics
418 mActions.addAction(
419 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
420 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
421 std::make_shared<AnalyticsActions::Function>(
422 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700423 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700424 }));
425
426 // Handle device use track statistics
427 mActions.addAction(
428 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
429 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
430 std::make_shared<AnalyticsActions::Function>(
431 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700432 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700433 }));
434
Andy Hungea840382020-05-05 21:50:17 -0700435
436 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700437
438 // We track connections (not disconnections) for the time to connect.
439 // TODO: consider BT requests in their A2dp service
440 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
441 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
442 // AudioDeviceBroker.postA2dpActiveDeviceChange
443 mActions.addAction(
444 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700445 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700446 std::make_shared<AnalyticsActions::Function>(
447 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
448 mDeviceConnection.a2dpConnected(item);
449 }));
450 // If audio is active, we expect to see a createAudioPatch after the device is connected.
451 mActions.addAction(
452 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
453 std::string("createAudioPatch"),
454 std::make_shared<AnalyticsActions::Function>(
455 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
456 mDeviceConnection.createPatch(item);
457 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800458
Andy Hungea840382020-05-05 21:50:17 -0700459 // Called from BT service
460 mActions.addAction(
461 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
462 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
463 "." AMEDIAMETRICS_PROP_STATE,
464 "connected",
465 std::make_shared<AnalyticsActions::Function>(
466 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
467 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
468 }));
469
Joey Poomarin52989982020-03-05 17:40:49 +0800470 // Handle power usage
471 mActions.addAction(
472 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
473 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
474 std::make_shared<AnalyticsActions::Function>(
475 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
476 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
477 }));
478
479 mActions.addAction(
480 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
481 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
482 std::make_shared<AnalyticsActions::Function>(
483 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
484 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
485 }));
486
487 mActions.addAction(
488 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
489 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
490 std::make_shared<AnalyticsActions::Function>(
491 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
492 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
493 mAudioPowerUsage.checkMode(item);
494 }));
495
496 mActions.addAction(
497 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
498 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
499 std::make_shared<AnalyticsActions::Function>(
500 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
501 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
502 mAudioPowerUsage.checkVoiceVolume(item);
503 }));
504
505 mActions.addAction(
506 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
507 std::string("createAudioPatch"),
508 std::make_shared<AnalyticsActions::Function>(
509 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
510 mAudioPowerUsage.checkCreatePatch(item);
511 }));
Andy Hunge0d43b42022-08-18 19:20:48 -0700512
513 // Handle Spatializer - these keys are prefixed by "audio.spatializer."
514 mActions.addAction(
515 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
516 std::monostate{}, /* match any event */
517 std::make_shared<AnalyticsActions::Function>(
518 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
519 mSpatializer.onEvent(item);
520 }));
Robert Wu38439732022-11-02 23:16:04 +0000521
522 // Handle MIDI
523 mActions.addAction(
524 AMEDIAMETRICS_KEY_AUDIO_MIDI "." AMEDIAMETRICS_PROP_EVENT,
525 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED),
526 std::make_shared<AnalyticsActions::Function>(
527 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
528 mMidiLogging.onEvent(item);
529 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800530}
531
532AudioAnalytics::~AudioAnalytics()
533{
534 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700535 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800536}
537
538status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800539 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800540{
Andy Hungea186fa2020-01-09 18:13:15 -0800541 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800542 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800543
544 // Status is selectively authenticated.
545 processStatus(item);
546
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800547 if (status != NO_ERROR) return status; // may not be permitted.
548
549 // Only if the item was successfully submitted (permission)
550 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800551 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800552 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800553}
554
Andy Hung709b91e2020-04-04 14:23:36 -0700555std::pair<std::string, int32_t> AudioAnalytics::dump(
556 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800557{
558 std::stringstream ss;
559 int32_t ll = lines;
560
561 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700562 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700563 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800564 ll -= l;
565 }
566 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800567 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800568 --ll;
569 }
570 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700571 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700572 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800573 ll -= l;
574 }
Joey Poomarin52989982020-03-05 17:40:49 +0800575
576 if (ll > 0 && prefix == nullptr) {
577 auto [s, l] = mAudioPowerUsage.dump(ll);
578 ss << s;
579 ll -= l;
580 }
Andy Hunga629bd12020-06-05 16:03:53 -0700581
Andy Hung06f3aba2019-12-03 16:36:42 -0800582 return { ss.str(), lines - ll };
583}
584
Andy Hung73dc2f92021-12-07 21:50:04 -0800585void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800586{
587 auto actions = mActions.getActionsForItem(item); // internally locked.
588 // Execute actions with no lock held.
589 for (const auto& action : actions) {
590 (*action)(item);
591 }
592}
593
Andy Hung73dc2f92021-12-07 21:50:04 -0800594void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
595{
596 int32_t status;
597 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
598
599 // Any record with a status will automatically be added to a heat map.
600 // Standard information.
601 const auto key = item->getKey();
602 const auto uid = item->getUid();
603
604 // from audio.track.10 -> prefix = audio.track, suffix = 10
605 // from audio.track.error -> prefix = audio.track, suffix = error
606 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
607
608 std::string message;
609 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
610
611 int32_t subCode = 0; // not used
612 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
613
614 std::string eventStr; // optional
615 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
616
617 const std::string statusString = extendedStatusToStatusString(status);
618
619 // Add to the heat map - we automatically track every item's status to see
620 // the types of errors and the frequency of errors.
621 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800622
Andy Hung44326582022-01-11 17:27:09 -0800623 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
624 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
625 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
626}
627
628bool AudioAnalytics::reportAudioRecordStatus(
629 const std::shared_ptr<const mediametrics::Item>& item,
630 const std::string& key, const std::string& eventStr,
631 const std::string& statusString, uid_t uid, const std::string& message,
632 int32_t subCode) const
633{
Andy Hungb8918b52021-12-14 22:15:40 -0800634 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800635 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
636 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
637 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
638
639 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000640 const int32_t event = stats::media_metrics::
Andy Hung44326582022-01-11 17:27:09 -0800641 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
642
643 // The following fields should all be present in a create event.
644 std::string flagsStr;
645 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
646 "%s: %s missing %s field", __func__,
647 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
648 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
649
650 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
651
652 std::string sourceStr;
653 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
654 "%s: %s missing %s field",
655 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
656 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
657
658 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
659
660 std::string encodingStr;
661 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
662 "%s: %s missing %s field",
663 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
664 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
665
666 int32_t channelMask = 0;
667 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
668 "%s: %s missing %s field",
669 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
670 int32_t frameCount = 0;
671 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
672 "%s: %s missing %s field",
673 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
674 int32_t sampleRate = 0;
675 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
676 "%s: %s missing %s field",
677 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
678
679 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000680 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
Andy Hung44326582022-01-11 17:27:09 -0800681 , atom_status
682 , message.c_str()
683 , subCode
684 , uid
685 , event
686 , flags
687 , source
688 , encoding
689 , (int64_t)channelMask
690 , frameCount
691 , sampleRate
692 );
693 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000694 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800695 return true;
696 }
697 return false;
698}
699
700bool AudioAnalytics::reportAudioTrackStatus(
701 const std::shared_ptr<const mediametrics::Item>& item,
702 const std::string& key, const std::string& eventStr,
703 const std::string& statusString, uid_t uid, const std::string& message,
704 int32_t subCode) const
705{
706 // Note that the prefixes often end with a '.' so we use startsWith.
707 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
708 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800709 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
710
711 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000712 const int32_t event = stats::media_metrics::
Andy Hungcb40b982022-01-31 20:08:25 -0800713 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800714
715 // The following fields should all be present in a create event.
716 std::string flagsStr;
717 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
718 "%s: %s missing %s field",
719 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
720 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
721
722 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
723
724 std::string contentTypeStr;
725 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
726 "%s: %s missing %s field",
727 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
728 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
729
730 std::string usageStr;
731 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
732 "%s: %s missing %s field",
733 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
734 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
735
736 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
737
738 std::string encodingStr;
739 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
740 "%s: %s missing %s field",
741 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
742 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
743
744 int32_t channelMask = 0;
745 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
746 "%s: %s missing %s field",
747 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
748 int32_t frameCount = 0;
749 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
750 "%s: %s missing %s field",
751 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
752 int32_t sampleRate = 0;
753 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
754 "%s: %s missing %s field",
755 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
756 double speed = 0.f; // default is 1.f
757 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
758 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800759 __func__,
760 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800761 double pitch = 0.f; // default is 1.f
762 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
763 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800764 __func__,
765 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800766 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000767 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
Andy Hungb8918b52021-12-14 22:15:40 -0800768 , atom_status
769 , message.c_str()
770 , subCode
771 , uid
772 , event
773 , flags
774 , contentType
775 , usage
776 , encoding
777 , (int64_t)channelMask
778 , frameCount
779 , sampleRate
780 , (float)speed
781 , (float)pitch
782 );
783 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000784 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800785 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800786 }
Andy Hung44326582022-01-11 17:27:09 -0800787 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800788}
789
Andy Hungea186fa2020-01-09 18:13:15 -0800790// HELPER METHODS
791
792std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
793{
794 int32_t threadId_int32{};
795 if (mAnalyticsState->timeMachine().get(
796 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
797 return {};
798 }
799 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
800}
801
Andy Hungce9b6632020-04-28 20:15:17 -0700802// DeviceUse helper class.
803void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700804 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700805 const std::string& key = item->getKey();
806 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700807 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
808 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
809 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700810 - 1);
811 // deliver statistics
812 int64_t deviceTimeNs = 0;
813 mAudioAnalytics.mAnalyticsState->timeMachine().get(
814 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
815 std::string encoding;
816 mAudioAnalytics.mAnalyticsState->timeMachine().get(
817 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
818 int32_t frameCount = 0;
819 mAudioAnalytics.mAnalyticsState->timeMachine().get(
820 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
821 int32_t intervalCount = 0;
822 mAudioAnalytics.mAnalyticsState->timeMachine().get(
823 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hungce9b6632020-04-28 20:15:17 -0700824 int32_t sampleRate = 0;
825 mAudioAnalytics.mAnalyticsState->timeMachine().get(
826 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700827 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700828 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700829 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700830
Andy Hungea840382020-05-05 21:50:17 -0700831 switch (itemType) {
832 case RECORD: {
Andy Hung76adef72022-09-14 17:24:19 -0700833 std::string inputDevicePairs;
834 mAudioAnalytics.mAnalyticsState->timeMachine().get(
835 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
836
837 const auto [ inputDeviceStatsd, inputDevices ] =
838 stringutils::parseInputDevicePairs(inputDevicePairs);
839 const std::string inputDeviceNames; // not filled currently.
840
Andy Hungea840382020-05-05 21:50:17 -0700841 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700842 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
843 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700844
Andy Hungea840382020-05-05 21:50:17 -0700845 std::string packageName;
846 int64_t versionCode = 0;
847 int32_t uid = -1;
848 mAudioAnalytics.mAnalyticsState->timeMachine().get(
849 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
850 if (uid != -1) {
851 std::tie(packageName, versionCode) =
852 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
853 }
854
855 int32_t selectedDeviceId = 0;
856 mAudioAnalytics.mAnalyticsState->timeMachine().get(
857 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
858 std::string source;
859 mAudioAnalytics.mAnalyticsState->timeMachine().get(
860 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800861 // Android S
862 std::string logSessionId;
863 mAudioAnalytics.mAnalyticsState->timeMachine().get(
864 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700865
Andy Hung1ea842e2020-05-18 10:47:31 -0700866 const auto callerNameForStats =
867 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
868 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
869 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
870 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800871 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700872 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700873
Andy Hunga629bd12020-06-05 16:03:53 -0700874 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700875 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700876 << " inputDevices:" << inputDevices << "(" << inputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -0700877 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700878 << " deviceTimeNs:" << deviceTimeNs
879 << " encoding:" << encoding << "(" << encodingForStats
880 << ") frameCount:" << frameCount
881 << " intervalCount:" << intervalCount
882 << " sampleRate:" << sampleRate
883 << " flags:" << flags << "(" << flagsForStats
884 << ") packageName:" << packageName
885 << " selectedDeviceId:" << selectedDeviceId
886 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800887 << ") source:" << source << "(" << sourceForStats
888 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
889 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700890 if (clientCalled // only log if client app called AudioRecord.
891 && mAudioAnalytics.mDeliverStatistics) {
892 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000893 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700894 , ENUM_EXTRACT(inputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -0700895 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700896 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700897 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700898 , frameCount
899 , intervalCount
900 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700901 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700902
903 , packageName.c_str()
904 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700905 , ENUM_EXTRACT(callerNameForStats)
906 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800907 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700908 );
Andy Hunga629bd12020-06-05 16:03:53 -0700909 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700910 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000911 stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700912 }
Andy Hungea840382020-05-05 21:50:17 -0700913 } break;
914 case THREAD: {
915 std::string type;
916 mAudioAnalytics.mAnalyticsState->timeMachine().get(
917 key, AMEDIAMETRICS_PROP_TYPE, &type);
918 int32_t underrun = 0; // zero for record types
919 mAudioAnalytics.mAnalyticsState->timeMachine().get(
920 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700921
922 const bool isInput = types::isInputThreadType(type);
Andy Hung76adef72022-09-14 17:24:19 -0700923
924 // get device information
925 std::string devicePairs;
926 std::string deviceStatsd;
927 std::string devices;
928 std::string deviceNames;
929 if (isInput) {
930 // Note we get the "last" device which is the one associated with group.
931 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_INPUTDEVICES,
932 &devicePairs);
933 std::tie(deviceStatsd, devices) = stringutils::parseInputDevicePairs(devicePairs);
934 } else {
935 // Note we get the "last" device which is the one associated with group.
936 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_OUTPUTDEVICES,
937 &devicePairs);
938 std::tie(deviceStatsd, devices) = stringutils::parseOutputDevicePairs(devicePairs);
939 deviceNames = mAudioAnalytics.getDeviceNamesFromOutputDevices(devices);
940 }
941
Andy Hung1ea842e2020-05-18 10:47:31 -0700942 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
943 const auto flagsForStats =
944 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
945 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
946 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
947
Andy Hung76adef72022-09-14 17:24:19 -0700948 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700949 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700950 << " devices:" << devices << "(" << deviceStatsd
951 << ") deviceNames:" << deviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700952 << " deviceTimeNs:" << deviceTimeNs
953 << " encoding:" << encoding << "(" << encodingForStats
954 << ") frameCount:" << frameCount
955 << " intervalCount:" << intervalCount
956 << " sampleRate:" << sampleRate
957 << " underrun:" << underrun
958 << " flags:" << flags << "(" << flagsForStats
959 << ") type:" << type << "(" << typeForStats
960 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700961 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700962 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000963 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700964 , ENUM_EXTRACT(deviceStatsd)
965 , deviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700966 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700967 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700968 , frameCount
969 , intervalCount
970 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700971 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700972 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700973 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700974 );
Andy Hunga629bd12020-06-05 16:03:53 -0700975 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700976 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000977 stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700978 }
Andy Hungea840382020-05-05 21:50:17 -0700979 } break;
980 case TRACK: {
Andy Hung76adef72022-09-14 17:24:19 -0700981 std::string outputDevicePairs;
982 mAudioAnalytics.mAnalyticsState->timeMachine().get(
983 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
984
985 const auto [ outputDeviceStatsd, outputDevices ] =
986 stringutils::parseOutputDevicePairs(outputDevicePairs);
987 const std::string outputDeviceNames =
988 mAudioAnalytics.getDeviceNamesFromOutputDevices(outputDevices);
989
Andy Hungce9b6632020-04-28 20:15:17 -0700990 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700991 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
992 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
993
Andy Hungce9b6632020-04-28 20:15:17 -0700994 std::string contentType;
995 mAudioAnalytics.mAnalyticsState->timeMachine().get(
996 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
997 double deviceLatencyMs = 0.;
998 mAudioAnalytics.mAnalyticsState->timeMachine().get(
999 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
1000 double deviceStartupMs = 0.;
1001 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1002 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
1003 double deviceVolume = 0.;
1004 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1005 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
1006 std::string packageName;
1007 int64_t versionCode = 0;
1008 int32_t uid = -1;
1009 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1010 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
1011 if (uid != -1) {
1012 std::tie(packageName, versionCode) =
1013 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
1014 }
1015 double playbackPitch = 0.;
1016 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1017 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
1018 double playbackSpeed = 0.;
1019 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1020 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
1021 int32_t selectedDeviceId = 0;
1022 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1023 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -07001024 std::string streamType;
1025 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1026 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001027 std::string traits;
1028 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1029 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -07001030 int32_t underrun = 0;
1031 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1032 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -07001033 std::string usage;
1034 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1035 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001036 // Android S
1037 std::string logSessionId;
1038 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1039 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -07001040
Andy Hung1ea842e2020-05-18 10:47:31 -07001041 const auto callerNameForStats =
1042 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1043 const auto contentTypeForStats =
1044 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1045 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1046 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1047 const auto streamTypeForStats =
1048 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001049 const auto traitsForStats =
1050 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -07001051 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001052 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001053 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001054
Andy Hunga629bd12020-06-05 16:03:53 -07001055 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001056 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -07001057 << " outputDevices:" << outputDevices << "(" << outputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -07001058 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001059 << " deviceTimeNs:" << deviceTimeNs
1060 << " encoding:" << encoding << "(" << encodingForStats
1061 << ") frameCount:" << frameCount
1062 << " intervalCount:" << intervalCount
1063 << " sampleRate:" << sampleRate
1064 << " underrun:" << underrun
1065 << " flags:" << flags << "(" << flagsForStats
1066 << ") callerName:" << callerName << "(" << callerNameForStats
1067 << ") contentType:" << contentType << "(" << contentTypeForStats
1068 << ") deviceLatencyMs:" << deviceLatencyMs
1069 << " deviceStartupMs:" << deviceStartupMs
1070 << " deviceVolume:" << deviceVolume
1071 << " packageName:" << packageName
1072 << " playbackPitch:" << playbackPitch
1073 << " playbackSpeed:" << playbackSpeed
1074 << " selectedDeviceId:" << selectedDeviceId
1075 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001076 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001077 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001078 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001079 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001080 if (clientCalled // only log if client app called AudioTracks
1081 && mAudioAnalytics.mDeliverStatistics) {
1082 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001083 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -07001084 , ENUM_EXTRACT(outputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -07001085 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001086 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001087 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001088 , frameCount
1089 , intervalCount
1090 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001091 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001092 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001093 , packageName.c_str()
1094 , (float)deviceLatencyMs
1095 , (float)deviceStartupMs
1096 , (float)deviceVolume
1097 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001098 , ENUM_EXTRACT(streamTypeForStats)
1099 , ENUM_EXTRACT(usageForStats)
1100 , ENUM_EXTRACT(contentTypeForStats)
1101 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001102 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001103 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001104 );
Andy Hunga629bd12020-06-05 16:03:53 -07001105 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001106 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001107 stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001108 }
Andy Hungea840382020-05-05 21:50:17 -07001109 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001110 }
Andy Hungce9b6632020-04-28 20:15:17 -07001111}
1112
1113// DeviceConnection helper class.
1114void AudioAnalytics::DeviceConnection::a2dpConnected(
1115 const std::shared_ptr<const android::mediametrics::Item> &item) {
1116 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001117 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001118 {
1119 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001120 mA2dpConnectionServiceNs = atNs;
1121 ++mA2dpConnectionServices;
1122
1123 if (mA2dpConnectionRequestNs == 0) {
1124 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1125 }
1126 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001127 }
1128 std::string name;
1129 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001130 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1131 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001132}
1133
1134void AudioAnalytics::DeviceConnection::createPatch(
1135 const std::shared_ptr<const android::mediametrics::Item> &item) {
1136 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001137 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001138 const std::string& key = item->getKey();
1139 std::string outputDevices;
1140 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001141 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001142 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001143 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001144 if (mA2dpConnectionRequestNs == 0) {
1145 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001146 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001147 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001148 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001149 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001150
Andy Hungea840382020-05-05 21:50:17 -07001151 mA2dpConnectionRequestNs = 0;
1152 mA2dpConnectionServiceNs = 0;
1153 ++mA2dpConnectionSuccesses;
1154
Andy Hungc14ee142021-03-10 16:39:02 -08001155 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001156
1157 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1158 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1159
Andy Hunga629bd12020-06-05 16:03:53 -07001160 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001161 << " A2DP SUCCESS"
1162 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001163 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001164 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001165 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001166 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001167
1168 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001169 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001170 , ENUM_EXTRACT(inputDeviceBits)
1171 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001172 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001173 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1174 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001175 , /* connection_count */ 1
1176 );
Andy Hunga629bd12020-06-05 16:03:53 -07001177 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001178 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001179 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001180 }
Andy Hungce9b6632020-04-28 20:15:17 -07001181 }
1182}
1183
Andy Hungea840382020-05-05 21:50:17 -07001184// Called through AudioManager when the BT service wants to enable
1185void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1186 const std::shared_ptr<const android::mediametrics::Item> &item) {
1187 const int64_t atNs = item->getTimestamp();
1188 const std::string& key = item->getKey();
1189 std::string state;
1190 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1191 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001192
1193 std::string name;
1194 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001195 {
1196 std::lock_guard l(mLock);
1197 mA2dpConnectionRequestNs = atNs;
1198 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001199 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001200 }
Andy Hunga629bd12020-06-05 16:03:53 -07001201 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1202 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001203 // TODO: attempt to cancel a timed event, rather than let it expire.
1204 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1205}
1206
Andy Hungce9b6632020-04-28 20:15:17 -07001207void AudioAnalytics::DeviceConnection::expire() {
1208 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001209 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001210
Andy Hung1ea842e2020-05-18 10:47:31 -07001211 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001212 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1213 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1214
Andy Hungea840382020-05-05 21:50:17 -07001215 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001216 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001217
Andy Hunga629bd12020-06-05 16:03:53 -07001218 LOG(LOG_LEVEL) << "A2DP CANCEL"
1219 << " outputDevices:" << outputDeviceBits
1220 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001221 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001222 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001223 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001224 , ENUM_EXTRACT(inputDeviceBits)
1225 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001226 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001227 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001228 , /* connection_time_ms */ 0.f
1229 , /* connection_count */ 1
1230 );
Andy Hunga629bd12020-06-05 16:03:53 -07001231 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001232 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001233 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001234 }
Andy Hungea840382020-05-05 21:50:17 -07001235 return;
1236 }
1237
1238 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1239 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001240 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001241 mA2dpConnectionRequestNs = 0;
1242 mA2dpConnectionServiceNs = 0;
1243 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001244
Andy Hunga629bd12020-06-05 16:03:53 -07001245 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1246 << " outputDevices:" << outputDeviceBits
1247 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001248 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001249 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001250 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001251 , ENUM_EXTRACT(inputDeviceBits)
1252 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001253 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001254 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001255 , /* connection_time_ms */ 0.f
1256 , /* connection_count */ 1
1257 );
Andy Hunga629bd12020-06-05 16:03:53 -07001258 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001259 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001260 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001261 }
Andy Hungce9b6632020-04-28 20:15:17 -07001262}
1263
jiabin515eb092020-11-18 17:55:52 -08001264void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1265 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1266 const std::string& key = item->getKey();
1267
jiabin515eb092020-11-18 17:55:52 -08001268 std::string directionStr;
1269 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1270 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1271 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1272
1273 int32_t framesPerBurst = -1;
1274 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1275 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1276
1277 int32_t bufferSizeInFrames = -1;
1278 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1279 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1280
1281 int32_t bufferCapacityInFrames = -1;
1282 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1283 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1284
1285 int32_t channelCount = -1;
1286 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1287 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001288 if (channelCount == -1) {
1289 // Try to get channel count from channel mask. From the legacy path,
1290 // only channel mask are logged.
1291 int32_t channelMask = 0;
1292 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1293 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1294 if (channelMask != 0) {
1295 switch (direction) {
1296 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001297 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001298 break;
1299 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001300 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001301 break;
1302 default:
1303 ALOGW("Invalid direction %d", direction);
1304 }
1305 }
1306 }
jiabin515eb092020-11-18 17:55:52 -08001307
1308 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001309 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1310 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001311
1312 std::string perfModeRequestedStr;
1313 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1314 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1315 const auto perfModeRequested =
1316 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1317
jiabin97247ea2021-04-07 00:33:38 +00001318 std::string perfModeActualStr;
1319 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1320 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1321 const auto perfModeActual =
1322 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001323
jiabinc8da9032021-04-28 20:42:36 +00001324 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001325 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001326 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1327 const auto sharingModeActual =
1328 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001329
1330 int32_t xrunCount = -1;
1331 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1332 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1333
jiabin92c9a522021-02-12 22:37:42 +00001334 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001335 // TODO: only routed device id is logged, but no device type
1336
jiabin97247ea2021-04-07 00:33:38 +00001337 std::string formatAppStr;
1338 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001339 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001340 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001341
1342 std::string formatDeviceStr;
1343 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1344 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1345 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1346
jiabin92c9a522021-02-12 22:37:42 +00001347 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001348 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1349 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001350
jiabinc4c331c2021-03-23 17:11:01 +00001351 int32_t sampleRate = 0;
1352 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1353 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1354
1355 std::string contentTypeStr;
1356 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1357 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1358 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1359
jiabinc8da9032021-04-28 20:42:36 +00001360 std::string sharingModeRequestedStr;
1361 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1362 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1363 const auto sharingModeRequested =
1364 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1365
Robert Wuf49223c2023-01-26 23:07:02 +00001366 std::string formatHardwareStr;
1367 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1368 key, AMEDIAMETRICS_PROP_ENCODINGHARDWARE, &formatHardwareStr);
1369 const auto formatHardware = types::lookup<types::ENCODING, int32_t>(formatHardwareStr);
1370
1371 int32_t channelCountHardware = -1;
1372 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1373 key, AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE, &channelCountHardware);
1374
1375 int32_t sampleRateHardware = 0;
1376 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1377 key, AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE, &sampleRateHardware);
1378
jiabin515eb092020-11-18 17:55:52 -08001379 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001380 << " path:" << path
1381 << " direction:" << direction << "(" << directionStr << ")"
1382 << " frames_per_burst:" << framesPerBurst
1383 << " buffer_size:" << bufferSizeInFrames
1384 << " buffer_capacity:" << bufferCapacityInFrames
1385 << " channel_count:" << channelCount
1386 << " total_frames_transferred:" << totalFramesTransferred
1387 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001388 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001389 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001390 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001391 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001392 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001393 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001394 << " log_session_id: " << logSessionId
1395 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001396 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1397 << " sharing_requested:" << sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001398 << "(" << sharingModeRequestedStr << ")"
1399 << " format_hardware:" << formatHardware << "(" << formatHardwareStr << ")"
1400 << " channel_count_hardware:" << channelCountHardware
1401 << " sample_rate_hardware: " << sampleRateHardware;
jiabin515eb092020-11-18 17:55:52 -08001402
jiabin92c9a522021-02-12 22:37:42 +00001403 if (mAudioAnalytics.mDeliverStatistics) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001404 const stats::media_metrics::BytesField bf_serialized(
jiabin92c9a522021-02-12 22:37:42 +00001405 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1406 const auto result = sendToStatsd(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001407 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001408 , path
1409 , direction
1410 , framesPerBurst
1411 , bufferSizeInFrames
1412 , bufferCapacityInFrames
1413 , channelCount
1414 , totalFramesTransferred
1415 , perfModeRequested
1416 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001417 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001418 , xrunCount
1419 , bf_serialized
1420 , formatApp
1421 , formatDevice
1422 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001423 , sampleRate
1424 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001425 , sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001426 , formatHardware
1427 , channelCountHardware
1428 , sampleRateHardware
jiabin92c9a522021-02-12 22:37:42 +00001429 );
1430 std::stringstream ss;
1431 ss << "result:" << result;
1432 const auto fieldsStr = printFields(AAudioStreamFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001433 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001434 , path
1435 , direction
1436 , framesPerBurst
1437 , bufferSizeInFrames
1438 , bufferCapacityInFrames
1439 , channelCount
1440 , totalFramesTransferred
1441 , perfModeRequested
1442 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001443 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001444 , xrunCount
1445 , serializedDeviceTypes.c_str()
1446 , formatApp
1447 , formatDevice
1448 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001449 , sampleRate
1450 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001451 , sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001452 , formatHardware
1453 , channelCountHardware
1454 , sampleRateHardware
jiabin92c9a522021-02-12 22:37:42 +00001455 );
1456 ss << " " << fieldsStr;
1457 std::string str = ss.str();
1458 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001459 mAudioAnalytics.mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001460 }
jiabin515eb092020-11-18 17:55:52 -08001461}
1462
Andy Hungf4eaa462022-03-09 21:53:09 -08001463// Create new state, typically occurs after an AudioFlinger ctor event.
1464void AudioAnalytics::newState()
1465{
1466 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1467 *mAnalyticsState.get()));
1468 // Note: get returns shared_ptr temp, whose lifetime is extended
1469 // to end of full expression.
1470 mAnalyticsState->clear(); // TODO: filter the analytics state.
1471 // Perhaps report this.
1472
1473 // Set up a timer to expire the previous audio state to save space.
1474 // Use the transaction log size as a cookie to see if it is the
1475 // same as before. A benign race is possible where a state is cleared early.
1476 const size_t size = mPreviousAnalyticsState->transactionLog().size();
1477 mTimedAction.postIn(
1478 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1479 if (mPreviousAnalyticsState->transactionLog().size() == size) {
1480 ALOGD("expiring previous audio state after %d seconds.",
1481 PREVIOUS_STATE_EXPIRE_SEC);
1482 mPreviousAnalyticsState->clear(); // removes data from the state.
1483 }
1484 });
1485}
1486
1487void AudioAnalytics::Health::onAudioServerStart(Module module,
1488 const std::shared_ptr<const android::mediametrics::Item> &item)
1489{
1490 const auto nowTime = std::chrono::system_clock::now();
1491 if (module == Module::AUDIOFLINGER) {
1492 {
1493 std::lock_guard lg(mLock);
1494 // reset state on AudioFlinger construction.
1495 // AudioPolicy is created after AudioFlinger.
1496 mAudioFlingerCtorTime = nowTime;
1497 mSimpleLog.log("AudioFlinger ctor");
1498 }
1499 mAudioAnalytics.newState();
1500 return;
1501 }
1502 if (module == Module::AUDIOPOLICY) {
1503 // A start event occurs when audioserver
1504 //
1505 // (1) Starts the first time
1506 // (2) Restarts because of the TimeCheck watchdog
1507 // (3) Restarts not because of the TimeCheck watchdog.
1508 int64_t executionTimeNs = 0;
1509 (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1510 const float loadTimeMs = executionTimeNs * 1e-6f;
1511 std::lock_guard lg(mLock);
1512 const int64_t restarts = mStartCount;
1513 if (mStopCount == mStartCount) {
1514 mAudioPolicyCtorTime = nowTime;
1515 ++mStartCount;
1516 if (mStopCount == 0) {
1517 // (1) First time initialization.
1518 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1519 __func__, item->getKey().c_str(), loadTimeMs);
1520 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1521 } else {
1522 // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
1523 const float restartMs =
1524 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1525 mAudioFlingerCtorTime - mStopTime).count();
1526 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1527 "restarts:%lld restartMs:%f loadTimeMs:%f",
1528 __func__, item->getKey().c_str(),
1529 (long long)restarts, restartMs, loadTimeMs);
1530 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1531 (long long)restarts, restartMs, loadTimeMs);
1532 }
1533 } else {
1534 // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1535 // However we can estimate the uptime from the delta time from previous ctor.
1536 const float uptimeMs =
1537 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1538 nowTime - mAudioFlingerCtorTime).count();
1539 mStopCount = mStartCount;
1540 mAudioPolicyCtorTime = nowTime;
1541 ++mStartCount;
1542
1543 ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1544 "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1545 __func__, item->getKey().c_str(),
1546 (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1547 mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1548 "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1549 (long long)restarts, uptimeMs, loadTimeMs);
1550 }
1551 }
1552}
1553
1554void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1555 const std::shared_ptr<const android::mediametrics::Item> &item)
1556{
1557 std::string moduleName = getModuleName(module);
1558 int64_t methodCode{};
1559 std::string methodName;
1560 (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1561 (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1562
1563 std::lock_guard lg(mLock);
1564 if (mStopCount >= mStartCount) {
1565 ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1566 "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1567 __func__, item->getKey().c_str(), moduleName.c_str(),
1568 methodName.c_str(), (long long)methodCode,
1569 (long long)mStopCount, (long long)mStartCount);
1570 return;
1571 }
1572
1573 const int64_t restarts = mStartCount - 1;
1574 ++mStopCount;
1575 mStopTime = std::chrono::system_clock::now();
1576 const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1577 mStopTime - mAudioFlingerCtorTime).count();
1578 ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1579 __func__, item->getKey().c_str(), moduleName.c_str(),
1580 methodName.c_str(), (long long)methodCode,
1581 (long long)restarts, uptimeMs);
1582 mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1583 moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1584 (long long)restarts, uptimeMs);
1585}
1586
1587std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1588 int32_t lines, const char *prefix) const
1589{
1590 std::lock_guard lg(mLock);
1591 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1592 size_t n = std::count(s.begin(), s.end(), '\n');
1593 return { s, n };
1594}
1595
Andy Hung05874e82022-08-17 17:27:32 -07001596// Classifies the setting event for statsd (use generated statsd enums.proto constants).
1597static int32_t classifySettingEvent(bool isSetAlready, bool withinBoot) {
1598 if (isSetAlready) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001599 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_NORMAL;
Andy Hung05874e82022-08-17 17:27:32 -07001600 }
1601 if (withinBoot) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001602 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_BOOT;
Andy Hung05874e82022-08-17 17:27:32 -07001603 }
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001604 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_FIRST;
Andy Hung05874e82022-08-17 17:27:32 -07001605}
1606
Andy Hunge0d43b42022-08-18 19:20:48 -07001607void AudioAnalytics::Spatializer::onEvent(
1608 const std::shared_ptr<const android::mediametrics::Item> &item)
1609{
1610 const auto key = item->getKey();
1611
1612 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1613
1614 const std::string suffix =
1615 key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1616
1617 std::string eventStr; // optional - find the actual event string.
1618 (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1619
1620 const size_t delim = suffix.find('.'); // note could use split.
1621 if (delim == suffix.npos) {
1622 // on create with suffix == "0" for the first spatializer effect.
1623
1624 std::string headTrackingModes;
1625 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1626
1627 std::string levels;
1628 (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1629
1630 std::string modes;
1631 (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1632
Andy Hung05874e82022-08-17 17:27:32 -07001633 std::string channelMasks;
1634 (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASKS, &channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001635
1636 LOG(LOG_LEVEL) << "key:" << key
1637 << " headTrackingModes:" << headTrackingModes
1638 << " levels:" << levels
1639 << " modes:" << modes
Andy Hung05874e82022-08-17 17:27:32 -07001640 << " channelMasks:" << channelMasks
Andy Hunge0d43b42022-08-18 19:20:48 -07001641 ;
1642
1643 const std::vector<int32_t> headTrackingModesVector =
1644 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1645 const std::vector<int32_t> levelsVector =
1646 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1647 const std::vector<int32_t> modesVector =
1648 types::vectorFromMap(modes, types::getSpatializerModeMap());
Andy Hung05874e82022-08-17 17:27:32 -07001649 const std::vector<int64_t> channelMasksVector =
1650 types::channelMaskVectorFromString(channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001651
Andy Hung05874e82022-08-17 17:27:32 -07001652 const auto [ result, str ] = sendToStatsd(SpatializerCapabilitiesFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001653 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001654 , headTrackingModesVector
1655 , levelsVector
1656 , modesVector
1657 , channelMasksVector
1658 );
1659
1660 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001661 stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001662
1663 std::lock_guard lg(mLock);
Andy Hung05874e82022-08-17 17:27:32 -07001664 if (mFirstCreateTimeNs == 0) {
1665 // Only update the create time once to prevent audioserver restart
1666 // from looking like a boot.
1667 mFirstCreateTimeNs = item->getTimestamp();
1668 }
Andy Hunge0d43b42022-08-18 19:20:48 -07001669 mSimpleLog.log("%s suffix: %s item: %s",
1670 __func__, suffix.c_str(), item->toString().c_str());
1671 } else {
1672 std::string subtype = suffix.substr(0, delim);
1673 if (subtype != "device") return; // not a device.
1674
Andy Hung05874e82022-08-17 17:27:32 -07001675 const std::string deviceType = suffix.substr(std::size("device.") - 1);
Andy Hunge0d43b42022-08-18 19:20:48 -07001676
Andy Hung05874e82022-08-17 17:27:32 -07001677 const int32_t deviceTypeStatsd =
1678 types::lookup<types::AUDIO_DEVICE_INFO_TYPE, int32_t>(deviceType);
1679
1680 std::string address;
1681 (void)item->get(AMEDIAMETRICS_PROP_ADDRESS, &address);
Andy Hunge0d43b42022-08-18 19:20:48 -07001682 std::string enabled;
1683 (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1684 std::string hasHeadTracker;
1685 (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1686 std::string headTrackerEnabled;
1687 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1688
1689 std::lock_guard lg(mLock);
1690
1691 // Validate from our cached state
Andy Hung05874e82022-08-17 17:27:32 -07001692
1693 // Our deviceKey takes the device type and appends the address if any.
1694 // This distinguishes different wireless devices for the purposes of tracking.
1695 std::string deviceKey(deviceType);
1696 deviceKey.append("_").append(address);
1697 DeviceState& deviceState = mDeviceStateMap[deviceKey];
1698
1699 // check whether the settings event is within a certain time of spatializer creation.
1700 const bool withinBoot =
1701 item->getTimestamp() - mFirstCreateTimeNs < kBootDurationThreshold;
Andy Hunge0d43b42022-08-18 19:20:48 -07001702
1703 if (!enabled.empty()) {
1704 if (enabled != deviceState.enabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001705 const int32_t settingEventStatsd =
1706 classifySettingEvent(!deviceState.enabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001707 deviceState.enabled = enabled;
1708 const bool enabledStatsd = enabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001709 const auto [ result, str ] = sendToStatsd(SpatializerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001710 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001711 , deviceTypeStatsd
1712 , settingEventStatsd
1713 , enabledStatsd
1714 );
1715 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001716 stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001717 }
1718 }
1719 if (!hasHeadTracker.empty()) {
1720 if (hasHeadTracker != deviceState.hasHeadTracker) {
Andy Hung05874e82022-08-17 17:27:32 -07001721 const int32_t settingEventStatsd =
1722 classifySettingEvent(!deviceState.hasHeadTracker.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001723 deviceState.hasHeadTracker = hasHeadTracker;
1724 const bool supportedStatsd = hasHeadTracker == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001725 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceSupportedFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001726 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001727 , deviceTypeStatsd
1728 , settingEventStatsd
1729 , supportedStatsd
1730 );
1731 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001732 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001733 }
1734 }
1735 if (!headTrackerEnabled.empty()) {
1736 if (headTrackerEnabled != deviceState.headTrackerEnabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001737 const int32_t settingEventStatsd =
1738 classifySettingEvent(!deviceState.headTrackerEnabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001739 deviceState.headTrackerEnabled = headTrackerEnabled;
1740 const bool enabledStatsd = headTrackerEnabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001741 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001742 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001743 , deviceTypeStatsd
1744 , settingEventStatsd
1745 , enabledStatsd
1746 );
1747 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001748 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001749 }
1750 }
Andy Hung05874e82022-08-17 17:27:32 -07001751 mSimpleLog.log("%s deviceKey: %s item: %s",
1752 __func__, deviceKey.c_str(), item->toString().c_str());
Andy Hunge0d43b42022-08-18 19:20:48 -07001753 }
1754}
1755
1756std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1757 int32_t lines, const char *prefix) const
1758{
1759 std::lock_guard lg(mLock);
1760 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1761 size_t n = std::count(s.begin(), s.end(), '\n');
1762 return { s, n };
1763}
Andy Hungf4eaa462022-03-09 21:53:09 -08001764
Robert Wu38439732022-11-02 23:16:04 +00001765void AudioAnalytics::MidiLogging::onEvent(
1766 const std::shared_ptr<const android::mediametrics::Item> &item) const {
1767 const std::string& key = item->getKey();
1768
1769 const auto uid = item->getUid();
1770
1771 int32_t deviceId = -1;
1772 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1773 key, AMEDIAMETRICS_PROP_DEVICEID, &deviceId);
1774
1775 int32_t inputPortCount = -1;
1776 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1777 key, AMEDIAMETRICS_PROP_INPUTPORTCOUNT, &inputPortCount);
1778
1779 int32_t outputPortCount = -1;
1780 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1781 key, AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT, &outputPortCount);
1782
1783 int32_t hardwareType = -1;
1784 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1785 key, AMEDIAMETRICS_PROP_HARDWARETYPE, &hardwareType);
1786
1787 std::string isSharedString;
1788 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1789 key, AMEDIAMETRICS_PROP_ISSHARED, &isSharedString);
1790 const bool isShared = (isSharedString == "true");
1791
1792 std::string supportsMidiUmpString;
1793 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1794 key, AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP, &supportsMidiUmpString);
1795 const bool supportsMidiUmp = (supportsMidiUmpString == "true");
1796
1797 std::string usingAlsaString;
1798 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1799 key, AMEDIAMETRICS_PROP_USINGALSA, &usingAlsaString);
1800 const bool usingAlsa = (usingAlsaString == "true");
1801
1802 int64_t durationNs = -1;
1803 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1804 key, AMEDIAMETRICS_PROP_DURATIONNS, &durationNs);
1805
1806 int32_t openedCount = -1;
1807 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1808 key, AMEDIAMETRICS_PROP_OPENEDCOUNT, &openedCount);
1809
1810 int32_t closedCount = -1;
1811 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1812 key, AMEDIAMETRICS_PROP_CLOSEDCOUNT, &closedCount);
1813
1814 std::string deviceDisconnectedString;
1815 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1816 key, AMEDIAMETRICS_PROP_DEVICEDISCONNECTED, &deviceDisconnectedString);
1817 const bool deviceDisconnected = (deviceDisconnectedString == "true");
1818
1819 int32_t totalInputBytes = -1;
1820 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1821 key, AMEDIAMETRICS_PROP_TOTALINPUTBYTES, &totalInputBytes);
1822
1823 int32_t totalOutputBytes = -1;
1824 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1825 key, AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES, &totalOutputBytes);
1826
1827 LOG(LOG_LEVEL) << "key:" << key
1828 << " uid:" << uid
1829 << " id:" << deviceId
1830 << " input_port_count:" << inputPortCount
1831 << " output_port_count:" << outputPortCount
1832 << " device_type:" << hardwareType
1833 << " is_shared:" << isSharedString
1834 << " supports_ump:" << supportsMidiUmpString
1835 << " using_alsa:" << usingAlsaString
1836 << " duration_opened_ms:" << durationNs
1837 << " opened_count:" << openedCount
1838 << " closed_count:" << closedCount
1839 << " device_disconnected:" << deviceDisconnectedString
1840 << " total_input_bytes:" << totalInputBytes
1841 << " total_output_bytes:" << totalOutputBytes;
1842
1843 if (mAudioAnalytics.mDeliverStatistics) {
1844 const auto result = sendToStatsd(
1845 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1846 , uid
1847 , deviceId
1848 , inputPortCount
1849 , outputPortCount
1850 , hardwareType
1851 , isShared
1852 , supportsMidiUmp
1853 , usingAlsa
1854 , durationNs
1855 , openedCount
1856 , closedCount
1857 , deviceDisconnected
1858 , totalInputBytes
1859 , totalOutputBytes);
1860 std::stringstream ss;
1861 ss << "result:" << result;
1862 const auto fieldsStr = printFields(MidiDeviceCloseFields,
1863 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1864 , uid
1865 , deviceId
1866 , inputPortCount
1867 , outputPortCount
1868 , hardwareType
1869 , isShared
1870 , supportsMidiUmp
1871 , usingAlsa
1872 , durationNs
1873 , openedCount
1874 , closedCount
1875 , deviceDisconnected
1876 , totalInputBytes
1877 , totalOutputBytes);
1878 ss << " " << fieldsStr;
1879 std::string str = ss.str();
1880 ALOGV("%s: statsd %s", __func__, str.c_str());
1881 mAudioAnalytics.mStatsdLog->log(
1882 stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED, str);
1883 }
1884}
1885
Andy Hung76adef72022-09-14 17:24:19 -07001886// This method currently suppresses the name.
1887std::string AudioAnalytics::getDeviceNamesFromOutputDevices(std::string_view devices) const {
1888 std::string deviceNames;
1889 if (stringutils::hasBluetoothOutputDevice(devices)) {
1890 deviceNames = SUPPRESSED;
1891#if 0 // TODO(b/161554630) sanitize name
1892 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1893 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
1894 // Remove | if present
1895 stringutils::replace(deviceNames, "|", '?');
1896 if (deviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
1897 deviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
1898 }
1899#endif
1900 }
1901 return deviceNames;
1902}
1903
Andy Hung3ab1b322020-05-18 10:47:31 -07001904} // namespace android::mediametrics