blob: c01d46ee755b077bb3f894e112e71dfe80c6659d [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",
Robert Wue51e4df2023-02-15 21:46:12 +0000244 "uid",
Robert Wu8f8dc092023-07-07 15:56:35 +0000245 "sample_rate_client",
jiabin92c9a522021-02-12 22:37:42 +0000246};
247
Andy Hung05874e82022-08-17 17:27:32 -0700248static constexpr const char * HeadTrackerDeviceEnabledFields[] {
249 "mediametrics_headtrackerdeviceenabled_reported",
250 "type",
251 "event",
252 "enabled",
253};
254
255static constexpr const char * HeadTrackerDeviceSupportedFields[] {
256 "mediametrics_headtrackerdevicesupported_reported",
257 "type",
258 "event",
259 "supported",
260};
261
262static constexpr const char * SpatializerCapabilitiesFields[] {
263 "mediametrics_spatializer_reported",
264 "head_tracking_modes",
265 "spatializer_levels",
266 "spatializer_modes",
267 "channel_masks",
268};
269
270static constexpr const char * SpatializerDeviceEnabledFields[] {
271 "mediametrics_spatializerdeviceenabled_reported",
272 "type",
273 "event",
274 "enabled",
275};
276
Robert Wu38439732022-11-02 23:16:04 +0000277static constexpr const char * const MidiDeviceCloseFields[] {
278 "mediametrics_midi_device_close_reported",
279 "uid",
280 "midi_device_id",
281 "input_port_count",
282 "output_port_count",
283 "device_type",
284 "is_shared",
285 "supports_ump",
286 "using_alsa",
287 "duration_ns",
288 "opened_count",
289 "closed_count",
290 "device_disconnected",
291 "total_input_bytes",
292 "total_output_bytes",
293};
294
jiabin92c9a522021-02-12 22:37:42 +0000295/**
296 * printFields is a helper method that prints the fields and corresponding values
297 * in a human readable style.
298 */
299template <size_t N, typename ...Types>
300std::string printFields(const char * const (& fields)[N], Types ... args)
301{
302 std::stringstream ss;
303 ss << " { ";
304 stringutils::fieldPrint(ss, fields, args...);
305 ss << "}";
306 return ss.str();
307}
308
309/**
310 * sendToStatsd is a helper method that sends the arguments to statsd
311 */
312template <typename ...Types>
313int sendToStatsd(Types ... args)
314{
315 int result = 0;
316
317#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000318 result = stats::media_metrics::stats_write(args...);
jiabin92c9a522021-02-12 22:37:42 +0000319#endif
320 return result;
321}
jiabin515eb092020-11-18 17:55:52 -0800322
Andy Hunga629bd12020-06-05 16:03:53 -0700323/**
324 * sendToStatsd is a helper method that sends the arguments to statsd
325 * and returns a pair { result, summary_string }.
326 */
327template <size_t N, typename ...Types>
328std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
329{
330 int result = 0;
331 std::stringstream ss;
332
333#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000334 result = stats::media_metrics::stats_write(args...);
Andy Hunga629bd12020-06-05 16:03:53 -0700335 ss << "result:" << result;
336#endif
337 ss << " { ";
338 stringutils::fieldPrint(ss, fields, args...);
339 ss << "}";
340 return { result, ss.str() };
341}
Andy Hung06f3aba2019-12-03 16:36:42 -0800342
Andy Hung5be90c82021-03-30 14:30:20 -0700343AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700344 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700345 , mStatsdLog(statsdLog)
346 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800347{
Andy Hunga629bd12020-06-05 16:03:53 -0700348 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800349 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800350
351 // Add action to save AnalyticsState if audioserver is restarted.
Andy Hungf4eaa462022-03-09 21:53:09 -0800352 // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
353 // as well as TimeCheck events.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800354 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800355 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
356 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800357 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800358 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungf4eaa462022-03-09 21:53:09 -0800359 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
360 }));
361 mActions.addAction(
362 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
363 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
364 std::make_shared<AnalyticsActions::Function>(
365 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
366 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
367 }));
368 mActions.addAction(
369 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
370 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
371 std::make_shared<AnalyticsActions::Function>(
372 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
373 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
374 }));
375 mActions.addAction(
376 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
377 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
378 std::make_shared<AnalyticsActions::Function>(
379 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
380 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
Andy Hungea186fa2020-01-09 18:13:15 -0800381 }));
382
jiabin97247ea2021-04-07 00:33:38 +0000383 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800384 mActions.addAction(
385 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
386 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
387 std::make_shared<AnalyticsActions::Function>(
388 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
389 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
390 }));
391
jiabin97247ea2021-04-07 00:33:38 +0000392 // Handle legacy aaudio capture stream statistics
393 mActions.addAction(
394 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
395 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
396 std::make_shared<AnalyticsActions::Function>(
397 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
398 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
399 }));
400
jiabin515eb092020-11-18 17:55:52 -0800401 // Handle mmap aaudio stream statistics
402 mActions.addAction(
403 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
404 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
405 std::make_shared<AnalyticsActions::Function>(
406 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
407 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
408 }));
409
Andy Hungea840382020-05-05 21:50:17 -0700410 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800411 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700412 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
413 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800414 std::make_shared<AnalyticsActions::Function>(
415 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700416 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800417 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700418
419 // Handle device use thread statistics
420 mActions.addAction(
421 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
422 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
423 std::make_shared<AnalyticsActions::Function>(
424 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700425 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700426 }));
427
428 // Handle device use track statistics
429 mActions.addAction(
430 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
431 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
432 std::make_shared<AnalyticsActions::Function>(
433 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700434 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700435 }));
436
Andy Hungea840382020-05-05 21:50:17 -0700437
438 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700439
440 // We track connections (not disconnections) for the time to connect.
441 // TODO: consider BT requests in their A2dp service
442 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
443 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
444 // AudioDeviceBroker.postA2dpActiveDeviceChange
445 mActions.addAction(
446 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700447 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700448 std::make_shared<AnalyticsActions::Function>(
449 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
450 mDeviceConnection.a2dpConnected(item);
451 }));
452 // If audio is active, we expect to see a createAudioPatch after the device is connected.
453 mActions.addAction(
454 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
455 std::string("createAudioPatch"),
456 std::make_shared<AnalyticsActions::Function>(
457 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
458 mDeviceConnection.createPatch(item);
459 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800460
Andy Hungea840382020-05-05 21:50:17 -0700461 // Called from BT service
462 mActions.addAction(
463 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
464 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
465 "." AMEDIAMETRICS_PROP_STATE,
466 "connected",
467 std::make_shared<AnalyticsActions::Function>(
468 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
469 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
470 }));
471
Joey Poomarin52989982020-03-05 17:40:49 +0800472 // Handle power usage
473 mActions.addAction(
474 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
475 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
476 std::make_shared<AnalyticsActions::Function>(
477 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
478 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
479 }));
480
481 mActions.addAction(
482 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
483 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
484 std::make_shared<AnalyticsActions::Function>(
485 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
486 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
487 }));
488
489 mActions.addAction(
490 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
491 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
492 std::make_shared<AnalyticsActions::Function>(
493 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
494 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
495 mAudioPowerUsage.checkMode(item);
496 }));
497
498 mActions.addAction(
499 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
500 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
501 std::make_shared<AnalyticsActions::Function>(
502 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
503 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
504 mAudioPowerUsage.checkVoiceVolume(item);
505 }));
506
507 mActions.addAction(
508 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
509 std::string("createAudioPatch"),
510 std::make_shared<AnalyticsActions::Function>(
511 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
512 mAudioPowerUsage.checkCreatePatch(item);
513 }));
Andy Hunge0d43b42022-08-18 19:20:48 -0700514
515 // Handle Spatializer - these keys are prefixed by "audio.spatializer."
516 mActions.addAction(
517 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
518 std::monostate{}, /* match any event */
519 std::make_shared<AnalyticsActions::Function>(
520 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
521 mSpatializer.onEvent(item);
522 }));
Robert Wu38439732022-11-02 23:16:04 +0000523
524 // Handle MIDI
525 mActions.addAction(
526 AMEDIAMETRICS_KEY_AUDIO_MIDI "." AMEDIAMETRICS_PROP_EVENT,
527 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED),
528 std::make_shared<AnalyticsActions::Function>(
529 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
530 mMidiLogging.onEvent(item);
531 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800532}
533
534AudioAnalytics::~AudioAnalytics()
535{
536 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700537 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800538}
539
540status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800541 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800542{
Andy Hungea186fa2020-01-09 18:13:15 -0800543 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800544 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800545
546 // Status is selectively authenticated.
547 processStatus(item);
548
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800549 if (status != NO_ERROR) return status; // may not be permitted.
550
551 // Only if the item was successfully submitted (permission)
552 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800553 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800554 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800555}
556
Andy Hung709b91e2020-04-04 14:23:36 -0700557std::pair<std::string, int32_t> AudioAnalytics::dump(
Andy Hunge4117002024-09-16 17:37:13 -0700558 bool details, int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800559{
560 std::stringstream ss;
561 int32_t ll = lines;
562
563 if (ll > 0) {
Andy Hunge4117002024-09-16 17:37:13 -0700564 auto [s, l] = mAnalyticsState->dump(details, ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700565 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800566 ll -= l;
567 }
Andy Hunge4117002024-09-16 17:37:13 -0700568
569 // use details to dump prior state.
570 if (details && ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800571 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800572 --ll;
573 }
Andy Hunge4117002024-09-16 17:37:13 -0700574 if (details && ll > 0) {
575 auto [s, l] = mPreviousAnalyticsState->dump(details, ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700576 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800577 ll -= l;
578 }
Joey Poomarin52989982020-03-05 17:40:49 +0800579
580 if (ll > 0 && prefix == nullptr) {
581 auto [s, l] = mAudioPowerUsage.dump(ll);
582 ss << s;
583 ll -= l;
584 }
Andy Hunga629bd12020-06-05 16:03:53 -0700585
Andy Hung06f3aba2019-12-03 16:36:42 -0800586 return { ss.str(), lines - ll };
587}
588
Andy Hung73dc2f92021-12-07 21:50:04 -0800589void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800590{
591 auto actions = mActions.getActionsForItem(item); // internally locked.
592 // Execute actions with no lock held.
593 for (const auto& action : actions) {
594 (*action)(item);
595 }
596}
597
Andy Hung73dc2f92021-12-07 21:50:04 -0800598void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
599{
600 int32_t status;
601 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
602
603 // Any record with a status will automatically be added to a heat map.
604 // Standard information.
605 const auto key = item->getKey();
606 const auto uid = item->getUid();
607
608 // from audio.track.10 -> prefix = audio.track, suffix = 10
609 // from audio.track.error -> prefix = audio.track, suffix = error
610 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
611
612 std::string message;
613 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
614
615 int32_t subCode = 0; // not used
616 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
617
618 std::string eventStr; // optional
619 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
620
621 const std::string statusString = extendedStatusToStatusString(status);
622
623 // Add to the heat map - we automatically track every item's status to see
624 // the types of errors and the frequency of errors.
625 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800626
Andy Hung44326582022-01-11 17:27:09 -0800627 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
628 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
629 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
630}
631
632bool AudioAnalytics::reportAudioRecordStatus(
633 const std::shared_ptr<const mediametrics::Item>& item,
634 const std::string& key, const std::string& eventStr,
635 const std::string& statusString, uid_t uid, const std::string& message,
636 int32_t subCode) const
637{
Andy Hungb8918b52021-12-14 22:15:40 -0800638 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800639 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
640 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
641 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
642
643 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000644 const int32_t event = stats::media_metrics::
Andy Hung44326582022-01-11 17:27:09 -0800645 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
646
647 // The following fields should all be present in a create event.
648 std::string flagsStr;
649 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
650 "%s: %s missing %s field", __func__,
651 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
652 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
653
654 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
655
656 std::string sourceStr;
657 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
658 "%s: %s missing %s field",
659 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
660 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
661
662 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
663
664 std::string encodingStr;
665 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
666 "%s: %s missing %s field",
667 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
668 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
669
670 int32_t channelMask = 0;
671 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
672 "%s: %s missing %s field",
673 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
674 int32_t frameCount = 0;
675 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
676 "%s: %s missing %s field",
677 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
678 int32_t sampleRate = 0;
679 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
680 "%s: %s missing %s field",
681 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
682
683 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000684 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
Andy Hung44326582022-01-11 17:27:09 -0800685 , atom_status
686 , message.c_str()
687 , subCode
688 , uid
689 , event
690 , flags
691 , source
692 , encoding
693 , (int64_t)channelMask
694 , frameCount
695 , sampleRate
696 );
697 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000698 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800699 return true;
700 }
701 return false;
702}
703
704bool AudioAnalytics::reportAudioTrackStatus(
705 const std::shared_ptr<const mediametrics::Item>& item,
706 const std::string& key, const std::string& eventStr,
707 const std::string& statusString, uid_t uid, const std::string& message,
708 int32_t subCode) const
709{
710 // Note that the prefixes often end with a '.' so we use startsWith.
711 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
712 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800713 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
714
715 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000716 const int32_t event = stats::media_metrics::
Andy Hungcb40b982022-01-31 20:08:25 -0800717 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800718
719 // The following fields should all be present in a create event.
720 std::string flagsStr;
721 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
722 "%s: %s missing %s field",
723 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
724 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
725
726 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
727
728 std::string contentTypeStr;
729 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
730 "%s: %s missing %s field",
731 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
732 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
733
734 std::string usageStr;
735 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
736 "%s: %s missing %s field",
737 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
738 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
739
740 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
741
742 std::string encodingStr;
743 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
744 "%s: %s missing %s field",
745 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
746 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
747
748 int32_t channelMask = 0;
749 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
750 "%s: %s missing %s field",
751 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
752 int32_t frameCount = 0;
753 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
754 "%s: %s missing %s field",
755 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
756 int32_t sampleRate = 0;
757 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
758 "%s: %s missing %s field",
759 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
760 double speed = 0.f; // default is 1.f
761 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
762 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800763 __func__,
764 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800765 double pitch = 0.f; // default is 1.f
766 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
767 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800768 __func__,
769 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800770 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000771 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
Andy Hungb8918b52021-12-14 22:15:40 -0800772 , atom_status
773 , message.c_str()
774 , subCode
775 , uid
776 , event
777 , flags
778 , contentType
779 , usage
780 , encoding
781 , (int64_t)channelMask
782 , frameCount
783 , sampleRate
784 , (float)speed
785 , (float)pitch
786 );
787 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000788 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800789 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800790 }
Andy Hung44326582022-01-11 17:27:09 -0800791 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800792}
793
Andy Hungea186fa2020-01-09 18:13:15 -0800794// HELPER METHODS
795
796std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
797{
798 int32_t threadId_int32{};
799 if (mAnalyticsState->timeMachine().get(
800 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
801 return {};
802 }
803 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
804}
805
Andy Hungce9b6632020-04-28 20:15:17 -0700806// DeviceUse helper class.
807void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700808 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700809 const std::string& key = item->getKey();
810 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700811 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
812 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
813 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700814 - 1);
815 // deliver statistics
816 int64_t deviceTimeNs = 0;
817 mAudioAnalytics.mAnalyticsState->timeMachine().get(
818 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
819 std::string encoding;
820 mAudioAnalytics.mAnalyticsState->timeMachine().get(
821 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
822 int32_t frameCount = 0;
823 mAudioAnalytics.mAnalyticsState->timeMachine().get(
824 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
825 int32_t intervalCount = 0;
826 mAudioAnalytics.mAnalyticsState->timeMachine().get(
827 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hungce9b6632020-04-28 20:15:17 -0700828 int32_t sampleRate = 0;
829 mAudioAnalytics.mAnalyticsState->timeMachine().get(
830 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700831 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700832 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700833 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700834
Andy Hungea840382020-05-05 21:50:17 -0700835 switch (itemType) {
836 case RECORD: {
Andy Hung76adef72022-09-14 17:24:19 -0700837 std::string inputDevicePairs;
838 mAudioAnalytics.mAnalyticsState->timeMachine().get(
839 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
840
841 const auto [ inputDeviceStatsd, inputDevices ] =
842 stringutils::parseInputDevicePairs(inputDevicePairs);
843 const std::string inputDeviceNames; // not filled currently.
844
Andy Hungea840382020-05-05 21:50:17 -0700845 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700846 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
847 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700848
Andy Hungea840382020-05-05 21:50:17 -0700849 std::string packageName;
850 int64_t versionCode = 0;
851 int32_t uid = -1;
852 mAudioAnalytics.mAnalyticsState->timeMachine().get(
853 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
854 if (uid != -1) {
855 std::tie(packageName, versionCode) =
856 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
857 }
858
859 int32_t selectedDeviceId = 0;
860 mAudioAnalytics.mAnalyticsState->timeMachine().get(
861 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
862 std::string source;
863 mAudioAnalytics.mAnalyticsState->timeMachine().get(
864 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800865 // Android S
866 std::string logSessionId;
867 mAudioAnalytics.mAnalyticsState->timeMachine().get(
868 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700869
Andy Hung1ea842e2020-05-18 10:47:31 -0700870 const auto callerNameForStats =
871 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
872 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
873 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
874 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800875 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700876 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700877
Andy Hunga629bd12020-06-05 16:03:53 -0700878 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700879 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700880 << " inputDevices:" << inputDevices << "(" << inputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -0700881 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700882 << " deviceTimeNs:" << deviceTimeNs
883 << " encoding:" << encoding << "(" << encodingForStats
884 << ") frameCount:" << frameCount
885 << " intervalCount:" << intervalCount
886 << " sampleRate:" << sampleRate
887 << " flags:" << flags << "(" << flagsForStats
888 << ") packageName:" << packageName
889 << " selectedDeviceId:" << selectedDeviceId
890 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800891 << ") source:" << source << "(" << sourceForStats
892 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
893 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700894 if (clientCalled // only log if client app called AudioRecord.
895 && mAudioAnalytics.mDeliverStatistics) {
896 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000897 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700898 , ENUM_EXTRACT(inputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -0700899 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700900 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700901 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700902 , frameCount
903 , intervalCount
904 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700905 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700906
907 , packageName.c_str()
908 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700909 , ENUM_EXTRACT(callerNameForStats)
910 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800911 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700912 );
Andy Hunga629bd12020-06-05 16:03:53 -0700913 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700914 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000915 stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700916 }
Andy Hungea840382020-05-05 21:50:17 -0700917 } break;
918 case THREAD: {
919 std::string type;
920 mAudioAnalytics.mAnalyticsState->timeMachine().get(
921 key, AMEDIAMETRICS_PROP_TYPE, &type);
922 int32_t underrun = 0; // zero for record types
923 mAudioAnalytics.mAnalyticsState->timeMachine().get(
924 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700925
926 const bool isInput = types::isInputThreadType(type);
Andy Hung76adef72022-09-14 17:24:19 -0700927
928 // get device information
929 std::string devicePairs;
930 std::string deviceStatsd;
931 std::string devices;
932 std::string deviceNames;
933 if (isInput) {
934 // Note we get the "last" device which is the one associated with group.
935 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_INPUTDEVICES,
936 &devicePairs);
937 std::tie(deviceStatsd, devices) = stringutils::parseInputDevicePairs(devicePairs);
938 } else {
939 // Note we get the "last" device which is the one associated with group.
940 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_OUTPUTDEVICES,
941 &devicePairs);
942 std::tie(deviceStatsd, devices) = stringutils::parseOutputDevicePairs(devicePairs);
943 deviceNames = mAudioAnalytics.getDeviceNamesFromOutputDevices(devices);
944 }
945
Andy Hung1ea842e2020-05-18 10:47:31 -0700946 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
947 const auto flagsForStats =
948 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
949 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
950 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
951
Andy Hung76adef72022-09-14 17:24:19 -0700952 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700953 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700954 << " devices:" << devices << "(" << deviceStatsd
955 << ") deviceNames:" << deviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700956 << " deviceTimeNs:" << deviceTimeNs
957 << " encoding:" << encoding << "(" << encodingForStats
958 << ") frameCount:" << frameCount
959 << " intervalCount:" << intervalCount
960 << " sampleRate:" << sampleRate
961 << " underrun:" << underrun
962 << " flags:" << flags << "(" << flagsForStats
963 << ") type:" << type << "(" << typeForStats
964 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700965 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700966 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000967 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700968 , ENUM_EXTRACT(deviceStatsd)
969 , deviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700970 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700971 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700972 , frameCount
973 , intervalCount
974 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700975 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700976 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700977 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700978 );
Andy Hunga629bd12020-06-05 16:03:53 -0700979 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700980 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000981 stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700982 }
Andy Hungea840382020-05-05 21:50:17 -0700983 } break;
984 case TRACK: {
Andy Hung76adef72022-09-14 17:24:19 -0700985 std::string outputDevicePairs;
986 mAudioAnalytics.mAnalyticsState->timeMachine().get(
987 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
988
989 const auto [ outputDeviceStatsd, outputDevices ] =
990 stringutils::parseOutputDevicePairs(outputDevicePairs);
991 const std::string outputDeviceNames =
992 mAudioAnalytics.getDeviceNamesFromOutputDevices(outputDevices);
993
Andy Hungce9b6632020-04-28 20:15:17 -0700994 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700995 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
996 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
997
Andy Hungce9b6632020-04-28 20:15:17 -0700998 std::string contentType;
999 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1000 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
1001 double deviceLatencyMs = 0.;
1002 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1003 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
1004 double deviceStartupMs = 0.;
1005 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1006 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
1007 double deviceVolume = 0.;
1008 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1009 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
1010 std::string packageName;
1011 int64_t versionCode = 0;
1012 int32_t uid = -1;
1013 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1014 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
1015 if (uid != -1) {
1016 std::tie(packageName, versionCode) =
1017 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
1018 }
1019 double playbackPitch = 0.;
1020 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1021 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
1022 double playbackSpeed = 0.;
1023 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1024 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
1025 int32_t selectedDeviceId = 0;
1026 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1027 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -07001028 std::string streamType;
1029 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1030 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001031 std::string traits;
1032 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1033 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -07001034 int32_t underrun = 0;
1035 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1036 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -07001037 std::string usage;
1038 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1039 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001040 // Android S
1041 std::string logSessionId;
1042 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1043 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -07001044
Andy Hung1ea842e2020-05-18 10:47:31 -07001045 const auto callerNameForStats =
1046 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1047 const auto contentTypeForStats =
1048 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1049 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1050 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1051 const auto streamTypeForStats =
1052 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001053 const auto traitsForStats =
1054 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -07001055 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001056 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001057 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001058
Andy Hunga629bd12020-06-05 16:03:53 -07001059 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001060 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -07001061 << " outputDevices:" << outputDevices << "(" << outputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -07001062 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001063 << " deviceTimeNs:" << deviceTimeNs
1064 << " encoding:" << encoding << "(" << encodingForStats
1065 << ") frameCount:" << frameCount
1066 << " intervalCount:" << intervalCount
1067 << " sampleRate:" << sampleRate
1068 << " underrun:" << underrun
1069 << " flags:" << flags << "(" << flagsForStats
1070 << ") callerName:" << callerName << "(" << callerNameForStats
1071 << ") contentType:" << contentType << "(" << contentTypeForStats
1072 << ") deviceLatencyMs:" << deviceLatencyMs
1073 << " deviceStartupMs:" << deviceStartupMs
1074 << " deviceVolume:" << deviceVolume
1075 << " packageName:" << packageName
1076 << " playbackPitch:" << playbackPitch
1077 << " playbackSpeed:" << playbackSpeed
1078 << " selectedDeviceId:" << selectedDeviceId
1079 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001080 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001081 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001082 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001083 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001084 if (clientCalled // only log if client app called AudioTracks
1085 && mAudioAnalytics.mDeliverStatistics) {
1086 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001087 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -07001088 , ENUM_EXTRACT(outputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -07001089 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001090 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001091 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001092 , frameCount
1093 , intervalCount
1094 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001095 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001096 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001097 , packageName.c_str()
1098 , (float)deviceLatencyMs
1099 , (float)deviceStartupMs
1100 , (float)deviceVolume
1101 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001102 , ENUM_EXTRACT(streamTypeForStats)
1103 , ENUM_EXTRACT(usageForStats)
1104 , ENUM_EXTRACT(contentTypeForStats)
1105 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001106 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001107 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001108 );
Andy Hunga629bd12020-06-05 16:03:53 -07001109 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001110 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001111 stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001112 }
Andy Hungea840382020-05-05 21:50:17 -07001113 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001114 }
Andy Hungce9b6632020-04-28 20:15:17 -07001115}
1116
1117// DeviceConnection helper class.
1118void AudioAnalytics::DeviceConnection::a2dpConnected(
1119 const std::shared_ptr<const android::mediametrics::Item> &item) {
1120 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001121 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001122 {
1123 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001124 mA2dpConnectionServiceNs = atNs;
1125 ++mA2dpConnectionServices;
1126
1127 if (mA2dpConnectionRequestNs == 0) {
1128 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1129 }
1130 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001131 }
1132 std::string name;
1133 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001134 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1135 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001136}
1137
1138void AudioAnalytics::DeviceConnection::createPatch(
1139 const std::shared_ptr<const android::mediametrics::Item> &item) {
1140 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001141 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001142 const std::string& key = item->getKey();
1143 std::string outputDevices;
1144 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001145 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001146 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001147 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001148 if (mA2dpConnectionRequestNs == 0) {
1149 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001150 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001151 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001152 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001153 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001154
Andy Hungea840382020-05-05 21:50:17 -07001155 mA2dpConnectionRequestNs = 0;
1156 mA2dpConnectionServiceNs = 0;
1157 ++mA2dpConnectionSuccesses;
1158
Andy Hungc14ee142021-03-10 16:39:02 -08001159 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001160
1161 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1162 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1163
Andy Hunga629bd12020-06-05 16:03:53 -07001164 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001165 << " A2DP SUCCESS"
1166 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001167 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001168 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001169 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001170 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001171
1172 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001173 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001174 , ENUM_EXTRACT(inputDeviceBits)
1175 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001176 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001177 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1178 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001179 , /* connection_count */ 1
1180 );
Andy Hunga629bd12020-06-05 16:03:53 -07001181 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001182 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001183 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001184 }
Andy Hungce9b6632020-04-28 20:15:17 -07001185 }
1186}
1187
Andy Hungea840382020-05-05 21:50:17 -07001188// Called through AudioManager when the BT service wants to enable
1189void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1190 const std::shared_ptr<const android::mediametrics::Item> &item) {
1191 const int64_t atNs = item->getTimestamp();
1192 const std::string& key = item->getKey();
1193 std::string state;
1194 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1195 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001196
1197 std::string name;
1198 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001199 {
1200 std::lock_guard l(mLock);
1201 mA2dpConnectionRequestNs = atNs;
1202 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001203 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001204 }
Andy Hunga629bd12020-06-05 16:03:53 -07001205 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1206 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001207 // TODO: attempt to cancel a timed event, rather than let it expire.
1208 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1209}
1210
Andy Hungce9b6632020-04-28 20:15:17 -07001211void AudioAnalytics::DeviceConnection::expire() {
1212 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001213 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001214
Andy Hung1ea842e2020-05-18 10:47:31 -07001215 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001216 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1217 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1218
Andy Hungea840382020-05-05 21:50:17 -07001219 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001220 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001221
Andy Hunga629bd12020-06-05 16:03:53 -07001222 LOG(LOG_LEVEL) << "A2DP CANCEL"
1223 << " outputDevices:" << outputDeviceBits
1224 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001225 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001226 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001227 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001228 , ENUM_EXTRACT(inputDeviceBits)
1229 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001230 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001231 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001232 , /* connection_time_ms */ 0.f
1233 , /* connection_count */ 1
1234 );
Andy Hunga629bd12020-06-05 16:03:53 -07001235 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001236 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001237 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001238 }
Andy Hungea840382020-05-05 21:50:17 -07001239 return;
1240 }
1241
1242 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1243 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001244 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001245 mA2dpConnectionRequestNs = 0;
1246 mA2dpConnectionServiceNs = 0;
1247 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001248
Andy Hunga629bd12020-06-05 16:03:53 -07001249 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1250 << " outputDevices:" << outputDeviceBits
1251 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001252 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001253 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001254 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001255 , ENUM_EXTRACT(inputDeviceBits)
1256 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001257 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001258 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001259 , /* connection_time_ms */ 0.f
1260 , /* connection_count */ 1
1261 );
Andy Hunga629bd12020-06-05 16:03:53 -07001262 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001263 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001264 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001265 }
Andy Hungce9b6632020-04-28 20:15:17 -07001266}
1267
jiabin515eb092020-11-18 17:55:52 -08001268void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1269 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1270 const std::string& key = item->getKey();
1271
jiabin515eb092020-11-18 17:55:52 -08001272 std::string directionStr;
1273 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1274 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1275 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1276
1277 int32_t framesPerBurst = -1;
1278 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1279 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1280
1281 int32_t bufferSizeInFrames = -1;
1282 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1283 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1284
1285 int32_t bufferCapacityInFrames = -1;
1286 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1287 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1288
1289 int32_t channelCount = -1;
1290 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1291 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001292 if (channelCount == -1) {
1293 // Try to get channel count from channel mask. From the legacy path,
1294 // only channel mask are logged.
1295 int32_t channelMask = 0;
1296 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1297 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1298 if (channelMask != 0) {
1299 switch (direction) {
1300 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001301 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001302 break;
1303 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001304 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001305 break;
1306 default:
1307 ALOGW("Invalid direction %d", direction);
1308 }
1309 }
1310 }
jiabin515eb092020-11-18 17:55:52 -08001311
1312 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001313 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1314 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001315
1316 std::string perfModeRequestedStr;
1317 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1318 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1319 const auto perfModeRequested =
1320 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1321
jiabin97247ea2021-04-07 00:33:38 +00001322 std::string perfModeActualStr;
1323 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1324 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1325 const auto perfModeActual =
1326 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001327
jiabinc8da9032021-04-28 20:42:36 +00001328 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001329 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001330 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1331 const auto sharingModeActual =
1332 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001333
1334 int32_t xrunCount = -1;
1335 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1336 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1337
jiabin92c9a522021-02-12 22:37:42 +00001338 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001339 // TODO: only routed device id is logged, but no device type
1340
jiabin97247ea2021-04-07 00:33:38 +00001341 std::string formatAppStr;
1342 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001343 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001344 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001345
1346 std::string formatDeviceStr;
1347 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1348 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1349 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1350
jiabin92c9a522021-02-12 22:37:42 +00001351 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001352 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1353 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001354
jiabinc4c331c2021-03-23 17:11:01 +00001355 int32_t sampleRate = 0;
1356 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1357 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1358
1359 std::string contentTypeStr;
1360 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1361 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1362 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1363
jiabinc8da9032021-04-28 20:42:36 +00001364 std::string sharingModeRequestedStr;
1365 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1366 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1367 const auto sharingModeRequested =
1368 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1369
Robert Wuf49223c2023-01-26 23:07:02 +00001370 std::string formatHardwareStr;
1371 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1372 key, AMEDIAMETRICS_PROP_ENCODINGHARDWARE, &formatHardwareStr);
1373 const auto formatHardware = types::lookup<types::ENCODING, int32_t>(formatHardwareStr);
1374
1375 int32_t channelCountHardware = -1;
1376 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1377 key, AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE, &channelCountHardware);
1378
1379 int32_t sampleRateHardware = 0;
1380 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1381 key, AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE, &sampleRateHardware);
1382
Robert Wue51e4df2023-02-15 21:46:12 +00001383 const auto uid = item->getUid();
1384
Robert Wu8f8dc092023-07-07 15:56:35 +00001385 int32_t sampleRateClient = 0;
1386 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1387 key, AMEDIAMETRICS_PROP_SAMPLERATECLIENT, &sampleRateClient);
1388
jiabin515eb092020-11-18 17:55:52 -08001389 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001390 << " path:" << path
1391 << " direction:" << direction << "(" << directionStr << ")"
1392 << " frames_per_burst:" << framesPerBurst
1393 << " buffer_size:" << bufferSizeInFrames
1394 << " buffer_capacity:" << bufferCapacityInFrames
1395 << " channel_count:" << channelCount
1396 << " total_frames_transferred:" << totalFramesTransferred
1397 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001398 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001399 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001400 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001401 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001402 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001403 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001404 << " log_session_id: " << logSessionId
1405 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001406 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1407 << " sharing_requested:" << sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001408 << "(" << sharingModeRequestedStr << ")"
1409 << " format_hardware:" << formatHardware << "(" << formatHardwareStr << ")"
1410 << " channel_count_hardware:" << channelCountHardware
Robert Wue51e4df2023-02-15 21:46:12 +00001411 << " sample_rate_hardware: " << sampleRateHardware
Robert Wu8f8dc092023-07-07 15:56:35 +00001412 << " uid: " << uid
1413 << " sample_rate_client: " << sampleRateClient;
jiabin515eb092020-11-18 17:55:52 -08001414
jiabin92c9a522021-02-12 22:37:42 +00001415 if (mAudioAnalytics.mDeliverStatistics) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001416 const stats::media_metrics::BytesField bf_serialized(
jiabin92c9a522021-02-12 22:37:42 +00001417 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1418 const auto result = sendToStatsd(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001419 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001420 , path
1421 , direction
1422 , framesPerBurst
1423 , bufferSizeInFrames
1424 , bufferCapacityInFrames
1425 , channelCount
1426 , totalFramesTransferred
1427 , perfModeRequested
1428 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001429 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001430 , xrunCount
1431 , bf_serialized
1432 , formatApp
1433 , formatDevice
1434 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001435 , sampleRate
1436 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001437 , sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001438 , formatHardware
1439 , channelCountHardware
1440 , sampleRateHardware
Robert Wue51e4df2023-02-15 21:46:12 +00001441 , uid
Robert Wu8f8dc092023-07-07 15:56:35 +00001442 , sampleRateClient
jiabin92c9a522021-02-12 22:37:42 +00001443 );
1444 std::stringstream ss;
1445 ss << "result:" << result;
1446 const auto fieldsStr = printFields(AAudioStreamFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001447 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001448 , path
1449 , direction
1450 , framesPerBurst
1451 , bufferSizeInFrames
1452 , bufferCapacityInFrames
1453 , channelCount
1454 , totalFramesTransferred
1455 , perfModeRequested
1456 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001457 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001458 , xrunCount
1459 , serializedDeviceTypes.c_str()
1460 , formatApp
1461 , formatDevice
1462 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001463 , sampleRate
1464 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001465 , sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001466 , formatHardware
1467 , channelCountHardware
1468 , sampleRateHardware
Robert Wue51e4df2023-02-15 21:46:12 +00001469 , uid
Robert Wu8f8dc092023-07-07 15:56:35 +00001470 , sampleRateClient
jiabin92c9a522021-02-12 22:37:42 +00001471 );
1472 ss << " " << fieldsStr;
1473 std::string str = ss.str();
1474 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001475 mAudioAnalytics.mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001476 }
jiabin515eb092020-11-18 17:55:52 -08001477}
1478
Andy Hungf4eaa462022-03-09 21:53:09 -08001479// Create new state, typically occurs after an AudioFlinger ctor event.
1480void AudioAnalytics::newState()
1481{
1482 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1483 *mAnalyticsState.get()));
1484 // Note: get returns shared_ptr temp, whose lifetime is extended
1485 // to end of full expression.
1486 mAnalyticsState->clear(); // TODO: filter the analytics state.
1487 // Perhaps report this.
1488
1489 // Set up a timer to expire the previous audio state to save space.
1490 // Use the transaction log size as a cookie to see if it is the
1491 // same as before. A benign race is possible where a state is cleared early.
1492 const size_t size = mPreviousAnalyticsState->transactionLog().size();
1493 mTimedAction.postIn(
1494 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1495 if (mPreviousAnalyticsState->transactionLog().size() == size) {
1496 ALOGD("expiring previous audio state after %d seconds.",
1497 PREVIOUS_STATE_EXPIRE_SEC);
1498 mPreviousAnalyticsState->clear(); // removes data from the state.
1499 }
1500 });
1501}
1502
1503void AudioAnalytics::Health::onAudioServerStart(Module module,
1504 const std::shared_ptr<const android::mediametrics::Item> &item)
1505{
1506 const auto nowTime = std::chrono::system_clock::now();
1507 if (module == Module::AUDIOFLINGER) {
1508 {
1509 std::lock_guard lg(mLock);
1510 // reset state on AudioFlinger construction.
1511 // AudioPolicy is created after AudioFlinger.
1512 mAudioFlingerCtorTime = nowTime;
1513 mSimpleLog.log("AudioFlinger ctor");
1514 }
1515 mAudioAnalytics.newState();
1516 return;
1517 }
1518 if (module == Module::AUDIOPOLICY) {
1519 // A start event occurs when audioserver
1520 //
1521 // (1) Starts the first time
1522 // (2) Restarts because of the TimeCheck watchdog
1523 // (3) Restarts not because of the TimeCheck watchdog.
1524 int64_t executionTimeNs = 0;
1525 (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1526 const float loadTimeMs = executionTimeNs * 1e-6f;
1527 std::lock_guard lg(mLock);
1528 const int64_t restarts = mStartCount;
1529 if (mStopCount == mStartCount) {
1530 mAudioPolicyCtorTime = nowTime;
1531 ++mStartCount;
1532 if (mStopCount == 0) {
1533 // (1) First time initialization.
1534 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1535 __func__, item->getKey().c_str(), loadTimeMs);
1536 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1537 } else {
1538 // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
1539 const float restartMs =
1540 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1541 mAudioFlingerCtorTime - mStopTime).count();
1542 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1543 "restarts:%lld restartMs:%f loadTimeMs:%f",
1544 __func__, item->getKey().c_str(),
1545 (long long)restarts, restartMs, loadTimeMs);
1546 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1547 (long long)restarts, restartMs, loadTimeMs);
1548 }
1549 } else {
1550 // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1551 // However we can estimate the uptime from the delta time from previous ctor.
1552 const float uptimeMs =
1553 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1554 nowTime - mAudioFlingerCtorTime).count();
1555 mStopCount = mStartCount;
1556 mAudioPolicyCtorTime = nowTime;
1557 ++mStartCount;
1558
1559 ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1560 "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1561 __func__, item->getKey().c_str(),
1562 (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1563 mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1564 "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1565 (long long)restarts, uptimeMs, loadTimeMs);
1566 }
1567 }
1568}
1569
1570void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1571 const std::shared_ptr<const android::mediametrics::Item> &item)
1572{
1573 std::string moduleName = getModuleName(module);
1574 int64_t methodCode{};
1575 std::string methodName;
1576 (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1577 (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1578
1579 std::lock_guard lg(mLock);
1580 if (mStopCount >= mStartCount) {
1581 ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1582 "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1583 __func__, item->getKey().c_str(), moduleName.c_str(),
1584 methodName.c_str(), (long long)methodCode,
1585 (long long)mStopCount, (long long)mStartCount);
1586 return;
1587 }
1588
1589 const int64_t restarts = mStartCount - 1;
1590 ++mStopCount;
1591 mStopTime = std::chrono::system_clock::now();
1592 const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1593 mStopTime - mAudioFlingerCtorTime).count();
1594 ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1595 __func__, item->getKey().c_str(), moduleName.c_str(),
1596 methodName.c_str(), (long long)methodCode,
1597 (long long)restarts, uptimeMs);
1598 mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1599 moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1600 (long long)restarts, uptimeMs);
1601}
1602
1603std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1604 int32_t lines, const char *prefix) const
1605{
1606 std::lock_guard lg(mLock);
1607 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1608 size_t n = std::count(s.begin(), s.end(), '\n');
1609 return { s, n };
1610}
1611
Andy Hung05874e82022-08-17 17:27:32 -07001612// Classifies the setting event for statsd (use generated statsd enums.proto constants).
1613static int32_t classifySettingEvent(bool isSetAlready, bool withinBoot) {
1614 if (isSetAlready) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001615 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_NORMAL;
Andy Hung05874e82022-08-17 17:27:32 -07001616 }
1617 if (withinBoot) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001618 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_BOOT;
Andy Hung05874e82022-08-17 17:27:32 -07001619 }
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001620 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_FIRST;
Andy Hung05874e82022-08-17 17:27:32 -07001621}
1622
Andy Hunge0d43b42022-08-18 19:20:48 -07001623void AudioAnalytics::Spatializer::onEvent(
1624 const std::shared_ptr<const android::mediametrics::Item> &item)
1625{
1626 const auto key = item->getKey();
1627
1628 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1629
1630 const std::string suffix =
1631 key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1632
1633 std::string eventStr; // optional - find the actual event string.
1634 (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1635
1636 const size_t delim = suffix.find('.'); // note could use split.
1637 if (delim == suffix.npos) {
1638 // on create with suffix == "0" for the first spatializer effect.
1639
1640 std::string headTrackingModes;
1641 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1642
1643 std::string levels;
1644 (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1645
1646 std::string modes;
1647 (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1648
Andy Hung05874e82022-08-17 17:27:32 -07001649 std::string channelMasks;
1650 (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASKS, &channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001651
1652 LOG(LOG_LEVEL) << "key:" << key
1653 << " headTrackingModes:" << headTrackingModes
1654 << " levels:" << levels
1655 << " modes:" << modes
Andy Hung05874e82022-08-17 17:27:32 -07001656 << " channelMasks:" << channelMasks
Andy Hunge0d43b42022-08-18 19:20:48 -07001657 ;
1658
1659 const std::vector<int32_t> headTrackingModesVector =
1660 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1661 const std::vector<int32_t> levelsVector =
1662 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1663 const std::vector<int32_t> modesVector =
1664 types::vectorFromMap(modes, types::getSpatializerModeMap());
Andy Hung05874e82022-08-17 17:27:32 -07001665 const std::vector<int64_t> channelMasksVector =
1666 types::channelMaskVectorFromString(channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001667
Andy Hung05874e82022-08-17 17:27:32 -07001668 const auto [ result, str ] = sendToStatsd(SpatializerCapabilitiesFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001669 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001670 , headTrackingModesVector
1671 , levelsVector
1672 , modesVector
1673 , channelMasksVector
1674 );
1675
1676 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001677 stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001678
1679 std::lock_guard lg(mLock);
Andy Hung05874e82022-08-17 17:27:32 -07001680 if (mFirstCreateTimeNs == 0) {
1681 // Only update the create time once to prevent audioserver restart
1682 // from looking like a boot.
1683 mFirstCreateTimeNs = item->getTimestamp();
1684 }
Andy Hunge0d43b42022-08-18 19:20:48 -07001685 mSimpleLog.log("%s suffix: %s item: %s",
1686 __func__, suffix.c_str(), item->toString().c_str());
1687 } else {
1688 std::string subtype = suffix.substr(0, delim);
1689 if (subtype != "device") return; // not a device.
1690
Andy Hung05874e82022-08-17 17:27:32 -07001691 const std::string deviceType = suffix.substr(std::size("device.") - 1);
Andy Hunge0d43b42022-08-18 19:20:48 -07001692
Andy Hung05874e82022-08-17 17:27:32 -07001693 const int32_t deviceTypeStatsd =
1694 types::lookup<types::AUDIO_DEVICE_INFO_TYPE, int32_t>(deviceType);
1695
1696 std::string address;
1697 (void)item->get(AMEDIAMETRICS_PROP_ADDRESS, &address);
Andy Hunge0d43b42022-08-18 19:20:48 -07001698 std::string enabled;
1699 (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1700 std::string hasHeadTracker;
1701 (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1702 std::string headTrackerEnabled;
1703 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1704
1705 std::lock_guard lg(mLock);
1706
1707 // Validate from our cached state
Andy Hung05874e82022-08-17 17:27:32 -07001708
1709 // Our deviceKey takes the device type and appends the address if any.
1710 // This distinguishes different wireless devices for the purposes of tracking.
1711 std::string deviceKey(deviceType);
1712 deviceKey.append("_").append(address);
1713 DeviceState& deviceState = mDeviceStateMap[deviceKey];
1714
1715 // check whether the settings event is within a certain time of spatializer creation.
1716 const bool withinBoot =
1717 item->getTimestamp() - mFirstCreateTimeNs < kBootDurationThreshold;
Andy Hunge0d43b42022-08-18 19:20:48 -07001718
1719 if (!enabled.empty()) {
1720 if (enabled != deviceState.enabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001721 const int32_t settingEventStatsd =
1722 classifySettingEvent(!deviceState.enabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001723 deviceState.enabled = enabled;
1724 const bool enabledStatsd = enabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001725 const auto [ result, str ] = sendToStatsd(SpatializerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001726 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001727 , deviceTypeStatsd
1728 , settingEventStatsd
1729 , enabledStatsd
1730 );
1731 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001732 stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001733 }
1734 }
1735 if (!hasHeadTracker.empty()) {
1736 if (hasHeadTracker != deviceState.hasHeadTracker) {
Andy Hung05874e82022-08-17 17:27:32 -07001737 const int32_t settingEventStatsd =
1738 classifySettingEvent(!deviceState.hasHeadTracker.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001739 deviceState.hasHeadTracker = hasHeadTracker;
1740 const bool supportedStatsd = hasHeadTracker == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001741 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceSupportedFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001742 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001743 , deviceTypeStatsd
1744 , settingEventStatsd
1745 , supportedStatsd
1746 );
1747 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001748 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001749 }
1750 }
1751 if (!headTrackerEnabled.empty()) {
1752 if (headTrackerEnabled != deviceState.headTrackerEnabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001753 const int32_t settingEventStatsd =
1754 classifySettingEvent(!deviceState.headTrackerEnabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001755 deviceState.headTrackerEnabled = headTrackerEnabled;
1756 const bool enabledStatsd = headTrackerEnabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001757 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001758 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001759 , deviceTypeStatsd
1760 , settingEventStatsd
1761 , enabledStatsd
1762 );
1763 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001764 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001765 }
1766 }
Andy Hung05874e82022-08-17 17:27:32 -07001767 mSimpleLog.log("%s deviceKey: %s item: %s",
1768 __func__, deviceKey.c_str(), item->toString().c_str());
Andy Hunge0d43b42022-08-18 19:20:48 -07001769 }
1770}
1771
1772std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1773 int32_t lines, const char *prefix) const
1774{
1775 std::lock_guard lg(mLock);
1776 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1777 size_t n = std::count(s.begin(), s.end(), '\n');
1778 return { s, n };
1779}
Andy Hungf4eaa462022-03-09 21:53:09 -08001780
Robert Wu38439732022-11-02 23:16:04 +00001781void AudioAnalytics::MidiLogging::onEvent(
1782 const std::shared_ptr<const android::mediametrics::Item> &item) const {
1783 const std::string& key = item->getKey();
1784
1785 const auto uid = item->getUid();
1786
1787 int32_t deviceId = -1;
1788 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1789 key, AMEDIAMETRICS_PROP_DEVICEID, &deviceId);
1790
1791 int32_t inputPortCount = -1;
1792 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1793 key, AMEDIAMETRICS_PROP_INPUTPORTCOUNT, &inputPortCount);
1794
1795 int32_t outputPortCount = -1;
1796 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1797 key, AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT, &outputPortCount);
1798
1799 int32_t hardwareType = -1;
1800 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1801 key, AMEDIAMETRICS_PROP_HARDWARETYPE, &hardwareType);
1802
1803 std::string isSharedString;
1804 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1805 key, AMEDIAMETRICS_PROP_ISSHARED, &isSharedString);
1806 const bool isShared = (isSharedString == "true");
1807
1808 std::string supportsMidiUmpString;
1809 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1810 key, AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP, &supportsMidiUmpString);
1811 const bool supportsMidiUmp = (supportsMidiUmpString == "true");
1812
1813 std::string usingAlsaString;
1814 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1815 key, AMEDIAMETRICS_PROP_USINGALSA, &usingAlsaString);
1816 const bool usingAlsa = (usingAlsaString == "true");
1817
1818 int64_t durationNs = -1;
1819 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1820 key, AMEDIAMETRICS_PROP_DURATIONNS, &durationNs);
1821
1822 int32_t openedCount = -1;
1823 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1824 key, AMEDIAMETRICS_PROP_OPENEDCOUNT, &openedCount);
1825
1826 int32_t closedCount = -1;
1827 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1828 key, AMEDIAMETRICS_PROP_CLOSEDCOUNT, &closedCount);
1829
1830 std::string deviceDisconnectedString;
1831 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1832 key, AMEDIAMETRICS_PROP_DEVICEDISCONNECTED, &deviceDisconnectedString);
1833 const bool deviceDisconnected = (deviceDisconnectedString == "true");
1834
1835 int32_t totalInputBytes = -1;
1836 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1837 key, AMEDIAMETRICS_PROP_TOTALINPUTBYTES, &totalInputBytes);
1838
1839 int32_t totalOutputBytes = -1;
1840 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1841 key, AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES, &totalOutputBytes);
1842
1843 LOG(LOG_LEVEL) << "key:" << key
1844 << " uid:" << uid
1845 << " id:" << deviceId
1846 << " input_port_count:" << inputPortCount
1847 << " output_port_count:" << outputPortCount
1848 << " device_type:" << hardwareType
1849 << " is_shared:" << isSharedString
1850 << " supports_ump:" << supportsMidiUmpString
1851 << " using_alsa:" << usingAlsaString
1852 << " duration_opened_ms:" << durationNs
1853 << " opened_count:" << openedCount
1854 << " closed_count:" << closedCount
1855 << " device_disconnected:" << deviceDisconnectedString
1856 << " total_input_bytes:" << totalInputBytes
1857 << " total_output_bytes:" << totalOutputBytes;
1858
1859 if (mAudioAnalytics.mDeliverStatistics) {
1860 const auto result = sendToStatsd(
1861 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1862 , uid
1863 , deviceId
1864 , inputPortCount
1865 , outputPortCount
1866 , hardwareType
1867 , isShared
1868 , supportsMidiUmp
1869 , usingAlsa
1870 , durationNs
1871 , openedCount
1872 , closedCount
1873 , deviceDisconnected
1874 , totalInputBytes
1875 , totalOutputBytes);
1876 std::stringstream ss;
1877 ss << "result:" << result;
1878 const auto fieldsStr = printFields(MidiDeviceCloseFields,
1879 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1880 , uid
1881 , deviceId
1882 , inputPortCount
1883 , outputPortCount
1884 , hardwareType
1885 , isShared
1886 , supportsMidiUmp
1887 , usingAlsa
1888 , durationNs
1889 , openedCount
1890 , closedCount
1891 , deviceDisconnected
1892 , totalInputBytes
1893 , totalOutputBytes);
1894 ss << " " << fieldsStr;
1895 std::string str = ss.str();
1896 ALOGV("%s: statsd %s", __func__, str.c_str());
1897 mAudioAnalytics.mStatsdLog->log(
1898 stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED, str);
1899 }
1900}
1901
Andy Hung76adef72022-09-14 17:24:19 -07001902// This method currently suppresses the name.
1903std::string AudioAnalytics::getDeviceNamesFromOutputDevices(std::string_view devices) const {
1904 std::string deviceNames;
1905 if (stringutils::hasBluetoothOutputDevice(devices)) {
1906 deviceNames = SUPPRESSED;
1907#if 0 // TODO(b/161554630) sanitize name
1908 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1909 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
1910 // Remove | if present
1911 stringutils::replace(deviceNames, "|", '?');
1912 if (deviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
1913 deviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
1914 }
1915#endif
1916 }
1917 return deviceNames;
1918}
1919
Andy Hung3ab1b322020-05-18 10:47:31 -07001920} // namespace android::mediametrics