blob: 59d1ae467d84f65164336e750491cdde90d801a1 [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",
jiabin92c9a522021-02-12 22:37:42 +0000245};
246
Andy Hung05874e82022-08-17 17:27:32 -0700247static constexpr const char * HeadTrackerDeviceEnabledFields[] {
248 "mediametrics_headtrackerdeviceenabled_reported",
249 "type",
250 "event",
251 "enabled",
252};
253
254static constexpr const char * HeadTrackerDeviceSupportedFields[] {
255 "mediametrics_headtrackerdevicesupported_reported",
256 "type",
257 "event",
258 "supported",
259};
260
261static constexpr const char * SpatializerCapabilitiesFields[] {
262 "mediametrics_spatializer_reported",
263 "head_tracking_modes",
264 "spatializer_levels",
265 "spatializer_modes",
266 "channel_masks",
267};
268
269static constexpr const char * SpatializerDeviceEnabledFields[] {
270 "mediametrics_spatializerdeviceenabled_reported",
271 "type",
272 "event",
273 "enabled",
274};
275
Robert Wu38439732022-11-02 23:16:04 +0000276static constexpr const char * const MidiDeviceCloseFields[] {
277 "mediametrics_midi_device_close_reported",
278 "uid",
279 "midi_device_id",
280 "input_port_count",
281 "output_port_count",
282 "device_type",
283 "is_shared",
284 "supports_ump",
285 "using_alsa",
286 "duration_ns",
287 "opened_count",
288 "closed_count",
289 "device_disconnected",
290 "total_input_bytes",
291 "total_output_bytes",
292};
293
jiabin92c9a522021-02-12 22:37:42 +0000294/**
295 * printFields is a helper method that prints the fields and corresponding values
296 * in a human readable style.
297 */
298template <size_t N, typename ...Types>
299std::string printFields(const char * const (& fields)[N], Types ... args)
300{
301 std::stringstream ss;
302 ss << " { ";
303 stringutils::fieldPrint(ss, fields, args...);
304 ss << "}";
305 return ss.str();
306}
307
308/**
309 * sendToStatsd is a helper method that sends the arguments to statsd
310 */
311template <typename ...Types>
312int sendToStatsd(Types ... args)
313{
314 int result = 0;
315
316#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000317 result = stats::media_metrics::stats_write(args...);
jiabin92c9a522021-02-12 22:37:42 +0000318#endif
319 return result;
320}
jiabin515eb092020-11-18 17:55:52 -0800321
Andy Hunga629bd12020-06-05 16:03:53 -0700322/**
323 * sendToStatsd is a helper method that sends the arguments to statsd
324 * and returns a pair { result, summary_string }.
325 */
326template <size_t N, typename ...Types>
327std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
328{
329 int result = 0;
330 std::stringstream ss;
331
332#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000333 result = stats::media_metrics::stats_write(args...);
Andy Hunga629bd12020-06-05 16:03:53 -0700334 ss << "result:" << result;
335#endif
336 ss << " { ";
337 stringutils::fieldPrint(ss, fields, args...);
338 ss << "}";
339 return { result, ss.str() };
340}
Andy Hung06f3aba2019-12-03 16:36:42 -0800341
Andy Hung5be90c82021-03-30 14:30:20 -0700342AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700343 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700344 , mStatsdLog(statsdLog)
345 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800346{
Andy Hunga629bd12020-06-05 16:03:53 -0700347 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800348 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800349
350 // Add action to save AnalyticsState if audioserver is restarted.
Andy Hungf4eaa462022-03-09 21:53:09 -0800351 // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
352 // as well as TimeCheck events.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800353 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800354 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
355 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800356 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800357 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungf4eaa462022-03-09 21:53:09 -0800358 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
359 }));
360 mActions.addAction(
361 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
362 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
363 std::make_shared<AnalyticsActions::Function>(
364 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
365 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
366 }));
367 mActions.addAction(
368 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
369 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
370 std::make_shared<AnalyticsActions::Function>(
371 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
372 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
373 }));
374 mActions.addAction(
375 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
376 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
377 std::make_shared<AnalyticsActions::Function>(
378 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
379 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
Andy Hungea186fa2020-01-09 18:13:15 -0800380 }));
381
jiabin97247ea2021-04-07 00:33:38 +0000382 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800383 mActions.addAction(
384 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
385 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
386 std::make_shared<AnalyticsActions::Function>(
387 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
388 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
389 }));
390
jiabin97247ea2021-04-07 00:33:38 +0000391 // Handle legacy aaudio capture stream statistics
392 mActions.addAction(
393 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
394 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
395 std::make_shared<AnalyticsActions::Function>(
396 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
397 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
398 }));
399
jiabin515eb092020-11-18 17:55:52 -0800400 // Handle mmap aaudio stream statistics
401 mActions.addAction(
402 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
403 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
404 std::make_shared<AnalyticsActions::Function>(
405 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
406 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
407 }));
408
Andy Hungea840382020-05-05 21:50:17 -0700409 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800410 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700411 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
412 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800413 std::make_shared<AnalyticsActions::Function>(
414 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700415 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800416 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700417
418 // Handle device use thread statistics
419 mActions.addAction(
420 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
421 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
422 std::make_shared<AnalyticsActions::Function>(
423 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700424 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700425 }));
426
427 // Handle device use track statistics
428 mActions.addAction(
429 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
430 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
431 std::make_shared<AnalyticsActions::Function>(
432 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700433 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700434 }));
435
Andy Hungea840382020-05-05 21:50:17 -0700436
437 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700438
439 // We track connections (not disconnections) for the time to connect.
440 // TODO: consider BT requests in their A2dp service
441 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
442 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
443 // AudioDeviceBroker.postA2dpActiveDeviceChange
444 mActions.addAction(
445 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700446 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700447 std::make_shared<AnalyticsActions::Function>(
448 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
449 mDeviceConnection.a2dpConnected(item);
450 }));
451 // If audio is active, we expect to see a createAudioPatch after the device is connected.
452 mActions.addAction(
453 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
454 std::string("createAudioPatch"),
455 std::make_shared<AnalyticsActions::Function>(
456 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
457 mDeviceConnection.createPatch(item);
458 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800459
Andy Hungea840382020-05-05 21:50:17 -0700460 // Called from BT service
461 mActions.addAction(
462 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
463 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
464 "." AMEDIAMETRICS_PROP_STATE,
465 "connected",
466 std::make_shared<AnalyticsActions::Function>(
467 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
468 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
469 }));
470
Joey Poomarin52989982020-03-05 17:40:49 +0800471 // Handle power usage
472 mActions.addAction(
473 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
474 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
475 std::make_shared<AnalyticsActions::Function>(
476 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
477 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
478 }));
479
480 mActions.addAction(
481 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
482 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
483 std::make_shared<AnalyticsActions::Function>(
484 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
485 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
486 }));
487
488 mActions.addAction(
489 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
490 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
491 std::make_shared<AnalyticsActions::Function>(
492 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
493 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
494 mAudioPowerUsage.checkMode(item);
495 }));
496
497 mActions.addAction(
498 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
499 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
500 std::make_shared<AnalyticsActions::Function>(
501 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
502 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
503 mAudioPowerUsage.checkVoiceVolume(item);
504 }));
505
506 mActions.addAction(
507 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
508 std::string("createAudioPatch"),
509 std::make_shared<AnalyticsActions::Function>(
510 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
511 mAudioPowerUsage.checkCreatePatch(item);
512 }));
Andy Hunge0d43b42022-08-18 19:20:48 -0700513
514 // Handle Spatializer - these keys are prefixed by "audio.spatializer."
515 mActions.addAction(
516 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
517 std::monostate{}, /* match any event */
518 std::make_shared<AnalyticsActions::Function>(
519 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
520 mSpatializer.onEvent(item);
521 }));
Robert Wu38439732022-11-02 23:16:04 +0000522
523 // Handle MIDI
524 mActions.addAction(
525 AMEDIAMETRICS_KEY_AUDIO_MIDI "." AMEDIAMETRICS_PROP_EVENT,
526 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED),
527 std::make_shared<AnalyticsActions::Function>(
528 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
529 mMidiLogging.onEvent(item);
530 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800531}
532
533AudioAnalytics::~AudioAnalytics()
534{
535 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700536 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800537}
538
539status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800540 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800541{
Andy Hungea186fa2020-01-09 18:13:15 -0800542 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800543 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800544
545 // Status is selectively authenticated.
546 processStatus(item);
547
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800548 if (status != NO_ERROR) return status; // may not be permitted.
549
550 // Only if the item was successfully submitted (permission)
551 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800552 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800553 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800554}
555
Andy Hung709b91e2020-04-04 14:23:36 -0700556std::pair<std::string, int32_t> AudioAnalytics::dump(
557 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800558{
559 std::stringstream ss;
560 int32_t ll = lines;
561
562 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700563 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700564 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800565 ll -= l;
566 }
567 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800568 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800569 --ll;
570 }
571 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700572 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700573 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800574 ll -= l;
575 }
Joey Poomarin52989982020-03-05 17:40:49 +0800576
577 if (ll > 0 && prefix == nullptr) {
578 auto [s, l] = mAudioPowerUsage.dump(ll);
579 ss << s;
580 ll -= l;
581 }
Andy Hunga629bd12020-06-05 16:03:53 -0700582
Andy Hung06f3aba2019-12-03 16:36:42 -0800583 return { ss.str(), lines - ll };
584}
585
Andy Hung73dc2f92021-12-07 21:50:04 -0800586void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800587{
588 auto actions = mActions.getActionsForItem(item); // internally locked.
589 // Execute actions with no lock held.
590 for (const auto& action : actions) {
591 (*action)(item);
592 }
593}
594
Andy Hung73dc2f92021-12-07 21:50:04 -0800595void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
596{
597 int32_t status;
598 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
599
600 // Any record with a status will automatically be added to a heat map.
601 // Standard information.
602 const auto key = item->getKey();
603 const auto uid = item->getUid();
604
605 // from audio.track.10 -> prefix = audio.track, suffix = 10
606 // from audio.track.error -> prefix = audio.track, suffix = error
607 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
608
609 std::string message;
610 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
611
612 int32_t subCode = 0; // not used
613 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
614
615 std::string eventStr; // optional
616 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
617
618 const std::string statusString = extendedStatusToStatusString(status);
619
620 // Add to the heat map - we automatically track every item's status to see
621 // the types of errors and the frequency of errors.
622 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800623
Andy Hung44326582022-01-11 17:27:09 -0800624 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
625 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
626 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
627}
628
629bool AudioAnalytics::reportAudioRecordStatus(
630 const std::shared_ptr<const mediametrics::Item>& item,
631 const std::string& key, const std::string& eventStr,
632 const std::string& statusString, uid_t uid, const std::string& message,
633 int32_t subCode) const
634{
Andy Hungb8918b52021-12-14 22:15:40 -0800635 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800636 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
637 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
638 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
639
640 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000641 const int32_t event = stats::media_metrics::
Andy Hung44326582022-01-11 17:27:09 -0800642 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
643
644 // The following fields should all be present in a create event.
645 std::string flagsStr;
646 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
647 "%s: %s missing %s field", __func__,
648 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
649 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
650
651 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
652
653 std::string sourceStr;
654 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
655 "%s: %s missing %s field",
656 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
657 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
658
659 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
660
661 std::string encodingStr;
662 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
663 "%s: %s missing %s field",
664 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
665 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
666
667 int32_t channelMask = 0;
668 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
669 "%s: %s missing %s field",
670 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
671 int32_t frameCount = 0;
672 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
673 "%s: %s missing %s field",
674 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
675 int32_t sampleRate = 0;
676 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
677 "%s: %s missing %s field",
678 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
679
680 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000681 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
Andy Hung44326582022-01-11 17:27:09 -0800682 , atom_status
683 , message.c_str()
684 , subCode
685 , uid
686 , event
687 , flags
688 , source
689 , encoding
690 , (int64_t)channelMask
691 , frameCount
692 , sampleRate
693 );
694 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000695 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800696 return true;
697 }
698 return false;
699}
700
701bool AudioAnalytics::reportAudioTrackStatus(
702 const std::shared_ptr<const mediametrics::Item>& item,
703 const std::string& key, const std::string& eventStr,
704 const std::string& statusString, uid_t uid, const std::string& message,
705 int32_t subCode) const
706{
707 // Note that the prefixes often end with a '.' so we use startsWith.
708 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
709 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800710 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
711
712 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000713 const int32_t event = stats::media_metrics::
Andy Hungcb40b982022-01-31 20:08:25 -0800714 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800715
716 // The following fields should all be present in a create event.
717 std::string flagsStr;
718 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
719 "%s: %s missing %s field",
720 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
721 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
722
723 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
724
725 std::string contentTypeStr;
726 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
727 "%s: %s missing %s field",
728 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
729 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
730
731 std::string usageStr;
732 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
733 "%s: %s missing %s field",
734 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
735 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
736
737 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
738
739 std::string encodingStr;
740 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
741 "%s: %s missing %s field",
742 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
743 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
744
745 int32_t channelMask = 0;
746 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
747 "%s: %s missing %s field",
748 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
749 int32_t frameCount = 0;
750 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
751 "%s: %s missing %s field",
752 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
753 int32_t sampleRate = 0;
754 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
755 "%s: %s missing %s field",
756 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
757 double speed = 0.f; // default is 1.f
758 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
759 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800760 __func__,
761 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800762 double pitch = 0.f; // default is 1.f
763 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
764 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800765 __func__,
766 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800767 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000768 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
Andy Hungb8918b52021-12-14 22:15:40 -0800769 , atom_status
770 , message.c_str()
771 , subCode
772 , uid
773 , event
774 , flags
775 , contentType
776 , usage
777 , encoding
778 , (int64_t)channelMask
779 , frameCount
780 , sampleRate
781 , (float)speed
782 , (float)pitch
783 );
784 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000785 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800786 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800787 }
Andy Hung44326582022-01-11 17:27:09 -0800788 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800789}
790
Andy Hungea186fa2020-01-09 18:13:15 -0800791// HELPER METHODS
792
793std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
794{
795 int32_t threadId_int32{};
796 if (mAnalyticsState->timeMachine().get(
797 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
798 return {};
799 }
800 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
801}
802
Andy Hungce9b6632020-04-28 20:15:17 -0700803// DeviceUse helper class.
804void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700805 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700806 const std::string& key = item->getKey();
807 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700808 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
809 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
810 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700811 - 1);
812 // deliver statistics
813 int64_t deviceTimeNs = 0;
814 mAudioAnalytics.mAnalyticsState->timeMachine().get(
815 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
816 std::string encoding;
817 mAudioAnalytics.mAnalyticsState->timeMachine().get(
818 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
819 int32_t frameCount = 0;
820 mAudioAnalytics.mAnalyticsState->timeMachine().get(
821 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
822 int32_t intervalCount = 0;
823 mAudioAnalytics.mAnalyticsState->timeMachine().get(
824 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hungce9b6632020-04-28 20:15:17 -0700825 int32_t sampleRate = 0;
826 mAudioAnalytics.mAnalyticsState->timeMachine().get(
827 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700828 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700829 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700830 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700831
Andy Hungea840382020-05-05 21:50:17 -0700832 switch (itemType) {
833 case RECORD: {
Andy Hung76adef72022-09-14 17:24:19 -0700834 std::string inputDevicePairs;
835 mAudioAnalytics.mAnalyticsState->timeMachine().get(
836 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
837
838 const auto [ inputDeviceStatsd, inputDevices ] =
839 stringutils::parseInputDevicePairs(inputDevicePairs);
840 const std::string inputDeviceNames; // not filled currently.
841
Andy Hungea840382020-05-05 21:50:17 -0700842 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700843 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
844 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700845
Andy Hungea840382020-05-05 21:50:17 -0700846 std::string packageName;
847 int64_t versionCode = 0;
848 int32_t uid = -1;
849 mAudioAnalytics.mAnalyticsState->timeMachine().get(
850 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
851 if (uid != -1) {
852 std::tie(packageName, versionCode) =
853 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
854 }
855
856 int32_t selectedDeviceId = 0;
857 mAudioAnalytics.mAnalyticsState->timeMachine().get(
858 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
859 std::string source;
860 mAudioAnalytics.mAnalyticsState->timeMachine().get(
861 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800862 // Android S
863 std::string logSessionId;
864 mAudioAnalytics.mAnalyticsState->timeMachine().get(
865 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700866
Andy Hung1ea842e2020-05-18 10:47:31 -0700867 const auto callerNameForStats =
868 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
869 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
870 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
871 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800872 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700873 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700874
Andy Hunga629bd12020-06-05 16:03:53 -0700875 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700876 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700877 << " inputDevices:" << inputDevices << "(" << inputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -0700878 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700879 << " deviceTimeNs:" << deviceTimeNs
880 << " encoding:" << encoding << "(" << encodingForStats
881 << ") frameCount:" << frameCount
882 << " intervalCount:" << intervalCount
883 << " sampleRate:" << sampleRate
884 << " flags:" << flags << "(" << flagsForStats
885 << ") packageName:" << packageName
886 << " selectedDeviceId:" << selectedDeviceId
887 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800888 << ") source:" << source << "(" << sourceForStats
889 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
890 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700891 if (clientCalled // only log if client app called AudioRecord.
892 && mAudioAnalytics.mDeliverStatistics) {
893 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000894 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700895 , ENUM_EXTRACT(inputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -0700896 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700897 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700898 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700899 , frameCount
900 , intervalCount
901 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700902 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700903
904 , packageName.c_str()
905 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700906 , ENUM_EXTRACT(callerNameForStats)
907 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800908 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700909 );
Andy Hunga629bd12020-06-05 16:03:53 -0700910 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700911 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000912 stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700913 }
Andy Hungea840382020-05-05 21:50:17 -0700914 } break;
915 case THREAD: {
916 std::string type;
917 mAudioAnalytics.mAnalyticsState->timeMachine().get(
918 key, AMEDIAMETRICS_PROP_TYPE, &type);
919 int32_t underrun = 0; // zero for record types
920 mAudioAnalytics.mAnalyticsState->timeMachine().get(
921 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700922
923 const bool isInput = types::isInputThreadType(type);
Andy Hung76adef72022-09-14 17:24:19 -0700924
925 // get device information
926 std::string devicePairs;
927 std::string deviceStatsd;
928 std::string devices;
929 std::string deviceNames;
930 if (isInput) {
931 // Note we get the "last" device which is the one associated with group.
932 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_INPUTDEVICES,
933 &devicePairs);
934 std::tie(deviceStatsd, devices) = stringutils::parseInputDevicePairs(devicePairs);
935 } else {
936 // Note we get the "last" device which is the one associated with group.
937 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_OUTPUTDEVICES,
938 &devicePairs);
939 std::tie(deviceStatsd, devices) = stringutils::parseOutputDevicePairs(devicePairs);
940 deviceNames = mAudioAnalytics.getDeviceNamesFromOutputDevices(devices);
941 }
942
Andy Hung1ea842e2020-05-18 10:47:31 -0700943 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
944 const auto flagsForStats =
945 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
946 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
947 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
948
Andy Hung76adef72022-09-14 17:24:19 -0700949 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700950 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700951 << " devices:" << devices << "(" << deviceStatsd
952 << ") deviceNames:" << deviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700953 << " deviceTimeNs:" << deviceTimeNs
954 << " encoding:" << encoding << "(" << encodingForStats
955 << ") frameCount:" << frameCount
956 << " intervalCount:" << intervalCount
957 << " sampleRate:" << sampleRate
958 << " underrun:" << underrun
959 << " flags:" << flags << "(" << flagsForStats
960 << ") type:" << type << "(" << typeForStats
961 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700962 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700963 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000964 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700965 , ENUM_EXTRACT(deviceStatsd)
966 , deviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700967 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700968 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700969 , frameCount
970 , intervalCount
971 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700972 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700973 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700974 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700975 );
Andy Hunga629bd12020-06-05 16:03:53 -0700976 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700977 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000978 stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700979 }
Andy Hungea840382020-05-05 21:50:17 -0700980 } break;
981 case TRACK: {
Andy Hung76adef72022-09-14 17:24:19 -0700982 std::string outputDevicePairs;
983 mAudioAnalytics.mAnalyticsState->timeMachine().get(
984 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
985
986 const auto [ outputDeviceStatsd, outputDevices ] =
987 stringutils::parseOutputDevicePairs(outputDevicePairs);
988 const std::string outputDeviceNames =
989 mAudioAnalytics.getDeviceNamesFromOutputDevices(outputDevices);
990
Andy Hungce9b6632020-04-28 20:15:17 -0700991 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700992 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
993 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
994
Andy Hungce9b6632020-04-28 20:15:17 -0700995 std::string contentType;
996 mAudioAnalytics.mAnalyticsState->timeMachine().get(
997 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
998 double deviceLatencyMs = 0.;
999 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1000 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
1001 double deviceStartupMs = 0.;
1002 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1003 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
1004 double deviceVolume = 0.;
1005 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1006 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
1007 std::string packageName;
1008 int64_t versionCode = 0;
1009 int32_t uid = -1;
1010 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1011 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
1012 if (uid != -1) {
1013 std::tie(packageName, versionCode) =
1014 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
1015 }
1016 double playbackPitch = 0.;
1017 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1018 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
1019 double playbackSpeed = 0.;
1020 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1021 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
1022 int32_t selectedDeviceId = 0;
1023 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1024 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -07001025 std::string streamType;
1026 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1027 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001028 std::string traits;
1029 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1030 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -07001031 int32_t underrun = 0;
1032 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1033 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -07001034 std::string usage;
1035 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1036 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001037 // Android S
1038 std::string logSessionId;
1039 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1040 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -07001041
Andy Hung1ea842e2020-05-18 10:47:31 -07001042 const auto callerNameForStats =
1043 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1044 const auto contentTypeForStats =
1045 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1046 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1047 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1048 const auto streamTypeForStats =
1049 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001050 const auto traitsForStats =
1051 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -07001052 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001053 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001054 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001055
Andy Hunga629bd12020-06-05 16:03:53 -07001056 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001057 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -07001058 << " outputDevices:" << outputDevices << "(" << outputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -07001059 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001060 << " deviceTimeNs:" << deviceTimeNs
1061 << " encoding:" << encoding << "(" << encodingForStats
1062 << ") frameCount:" << frameCount
1063 << " intervalCount:" << intervalCount
1064 << " sampleRate:" << sampleRate
1065 << " underrun:" << underrun
1066 << " flags:" << flags << "(" << flagsForStats
1067 << ") callerName:" << callerName << "(" << callerNameForStats
1068 << ") contentType:" << contentType << "(" << contentTypeForStats
1069 << ") deviceLatencyMs:" << deviceLatencyMs
1070 << " deviceStartupMs:" << deviceStartupMs
1071 << " deviceVolume:" << deviceVolume
1072 << " packageName:" << packageName
1073 << " playbackPitch:" << playbackPitch
1074 << " playbackSpeed:" << playbackSpeed
1075 << " selectedDeviceId:" << selectedDeviceId
1076 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001077 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001078 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001079 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001080 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001081 if (clientCalled // only log if client app called AudioTracks
1082 && mAudioAnalytics.mDeliverStatistics) {
1083 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001084 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -07001085 , ENUM_EXTRACT(outputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -07001086 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001087 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001088 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001089 , frameCount
1090 , intervalCount
1091 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001092 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001093 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001094 , packageName.c_str()
1095 , (float)deviceLatencyMs
1096 , (float)deviceStartupMs
1097 , (float)deviceVolume
1098 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001099 , ENUM_EXTRACT(streamTypeForStats)
1100 , ENUM_EXTRACT(usageForStats)
1101 , ENUM_EXTRACT(contentTypeForStats)
1102 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001103 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001104 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001105 );
Andy Hunga629bd12020-06-05 16:03:53 -07001106 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001107 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001108 stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001109 }
Andy Hungea840382020-05-05 21:50:17 -07001110 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001111 }
Andy Hungce9b6632020-04-28 20:15:17 -07001112}
1113
1114// DeviceConnection helper class.
1115void AudioAnalytics::DeviceConnection::a2dpConnected(
1116 const std::shared_ptr<const android::mediametrics::Item> &item) {
1117 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001118 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001119 {
1120 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001121 mA2dpConnectionServiceNs = atNs;
1122 ++mA2dpConnectionServices;
1123
1124 if (mA2dpConnectionRequestNs == 0) {
1125 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1126 }
1127 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001128 }
1129 std::string name;
1130 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001131 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1132 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001133}
1134
1135void AudioAnalytics::DeviceConnection::createPatch(
1136 const std::shared_ptr<const android::mediametrics::Item> &item) {
1137 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001138 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001139 const std::string& key = item->getKey();
1140 std::string outputDevices;
1141 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001142 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001143 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001144 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001145 if (mA2dpConnectionRequestNs == 0) {
1146 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001147 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001148 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001149 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001150 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001151
Andy Hungea840382020-05-05 21:50:17 -07001152 mA2dpConnectionRequestNs = 0;
1153 mA2dpConnectionServiceNs = 0;
1154 ++mA2dpConnectionSuccesses;
1155
Andy Hungc14ee142021-03-10 16:39:02 -08001156 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001157
1158 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1159 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1160
Andy Hunga629bd12020-06-05 16:03:53 -07001161 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001162 << " A2DP SUCCESS"
1163 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001164 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001165 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001166 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001167 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001168
1169 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001170 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001171 , ENUM_EXTRACT(inputDeviceBits)
1172 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001173 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001174 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1175 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001176 , /* connection_count */ 1
1177 );
Andy Hunga629bd12020-06-05 16:03:53 -07001178 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001179 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001180 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001181 }
Andy Hungce9b6632020-04-28 20:15:17 -07001182 }
1183}
1184
Andy Hungea840382020-05-05 21:50:17 -07001185// Called through AudioManager when the BT service wants to enable
1186void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1187 const std::shared_ptr<const android::mediametrics::Item> &item) {
1188 const int64_t atNs = item->getTimestamp();
1189 const std::string& key = item->getKey();
1190 std::string state;
1191 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1192 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001193
1194 std::string name;
1195 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001196 {
1197 std::lock_guard l(mLock);
1198 mA2dpConnectionRequestNs = atNs;
1199 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001200 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001201 }
Andy Hunga629bd12020-06-05 16:03:53 -07001202 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1203 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001204 // TODO: attempt to cancel a timed event, rather than let it expire.
1205 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1206}
1207
Andy Hungce9b6632020-04-28 20:15:17 -07001208void AudioAnalytics::DeviceConnection::expire() {
1209 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001210 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001211
Andy Hung1ea842e2020-05-18 10:47:31 -07001212 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001213 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1214 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1215
Andy Hungea840382020-05-05 21:50:17 -07001216 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001217 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001218
Andy Hunga629bd12020-06-05 16:03:53 -07001219 LOG(LOG_LEVEL) << "A2DP CANCEL"
1220 << " outputDevices:" << outputDeviceBits
1221 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001222 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001223 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001224 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001225 , ENUM_EXTRACT(inputDeviceBits)
1226 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001227 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001228 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001229 , /* connection_time_ms */ 0.f
1230 , /* connection_count */ 1
1231 );
Andy Hunga629bd12020-06-05 16:03:53 -07001232 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001233 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001234 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001235 }
Andy Hungea840382020-05-05 21:50:17 -07001236 return;
1237 }
1238
1239 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1240 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001241 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001242 mA2dpConnectionRequestNs = 0;
1243 mA2dpConnectionServiceNs = 0;
1244 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001245
Andy Hunga629bd12020-06-05 16:03:53 -07001246 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1247 << " outputDevices:" << outputDeviceBits
1248 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001249 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001250 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001251 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001252 , ENUM_EXTRACT(inputDeviceBits)
1253 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001254 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001255 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001256 , /* connection_time_ms */ 0.f
1257 , /* connection_count */ 1
1258 );
Andy Hunga629bd12020-06-05 16:03:53 -07001259 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001260 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001261 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001262 }
Andy Hungce9b6632020-04-28 20:15:17 -07001263}
1264
jiabin515eb092020-11-18 17:55:52 -08001265void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1266 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1267 const std::string& key = item->getKey();
1268
jiabin515eb092020-11-18 17:55:52 -08001269 std::string directionStr;
1270 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1271 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1272 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1273
1274 int32_t framesPerBurst = -1;
1275 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1276 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1277
1278 int32_t bufferSizeInFrames = -1;
1279 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1280 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1281
1282 int32_t bufferCapacityInFrames = -1;
1283 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1284 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1285
1286 int32_t channelCount = -1;
1287 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1288 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001289 if (channelCount == -1) {
1290 // Try to get channel count from channel mask. From the legacy path,
1291 // only channel mask are logged.
1292 int32_t channelMask = 0;
1293 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1294 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1295 if (channelMask != 0) {
1296 switch (direction) {
1297 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001298 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001299 break;
1300 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001301 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001302 break;
1303 default:
1304 ALOGW("Invalid direction %d", direction);
1305 }
1306 }
1307 }
jiabin515eb092020-11-18 17:55:52 -08001308
1309 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001310 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1311 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001312
1313 std::string perfModeRequestedStr;
1314 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1315 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1316 const auto perfModeRequested =
1317 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1318
jiabin97247ea2021-04-07 00:33:38 +00001319 std::string perfModeActualStr;
1320 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1321 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1322 const auto perfModeActual =
1323 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001324
jiabinc8da9032021-04-28 20:42:36 +00001325 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001326 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001327 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1328 const auto sharingModeActual =
1329 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001330
1331 int32_t xrunCount = -1;
1332 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1333 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1334
jiabin92c9a522021-02-12 22:37:42 +00001335 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001336 // TODO: only routed device id is logged, but no device type
1337
jiabin97247ea2021-04-07 00:33:38 +00001338 std::string formatAppStr;
1339 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001340 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001341 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001342
1343 std::string formatDeviceStr;
1344 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1345 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1346 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1347
jiabin92c9a522021-02-12 22:37:42 +00001348 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001349 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1350 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001351
jiabinc4c331c2021-03-23 17:11:01 +00001352 int32_t sampleRate = 0;
1353 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1354 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1355
1356 std::string contentTypeStr;
1357 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1358 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1359 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1360
jiabinc8da9032021-04-28 20:42:36 +00001361 std::string sharingModeRequestedStr;
1362 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1363 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1364 const auto sharingModeRequested =
1365 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1366
Robert Wuf49223c2023-01-26 23:07:02 +00001367 std::string formatHardwareStr;
1368 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1369 key, AMEDIAMETRICS_PROP_ENCODINGHARDWARE, &formatHardwareStr);
1370 const auto formatHardware = types::lookup<types::ENCODING, int32_t>(formatHardwareStr);
1371
1372 int32_t channelCountHardware = -1;
1373 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1374 key, AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE, &channelCountHardware);
1375
1376 int32_t sampleRateHardware = 0;
1377 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1378 key, AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE, &sampleRateHardware);
1379
Robert Wue51e4df2023-02-15 21:46:12 +00001380 const auto uid = item->getUid();
1381
jiabin515eb092020-11-18 17:55:52 -08001382 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001383 << " path:" << path
1384 << " direction:" << direction << "(" << directionStr << ")"
1385 << " frames_per_burst:" << framesPerBurst
1386 << " buffer_size:" << bufferSizeInFrames
1387 << " buffer_capacity:" << bufferCapacityInFrames
1388 << " channel_count:" << channelCount
1389 << " total_frames_transferred:" << totalFramesTransferred
1390 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001391 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001392 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001393 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001394 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001395 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001396 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001397 << " log_session_id: " << logSessionId
1398 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001399 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1400 << " sharing_requested:" << sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001401 << "(" << sharingModeRequestedStr << ")"
1402 << " format_hardware:" << formatHardware << "(" << formatHardwareStr << ")"
1403 << " channel_count_hardware:" << channelCountHardware
Robert Wue51e4df2023-02-15 21:46:12 +00001404 << " sample_rate_hardware: " << sampleRateHardware
1405 << " uid: " << uid;
jiabin515eb092020-11-18 17:55:52 -08001406
jiabin92c9a522021-02-12 22:37:42 +00001407 if (mAudioAnalytics.mDeliverStatistics) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001408 const stats::media_metrics::BytesField bf_serialized(
jiabin92c9a522021-02-12 22:37:42 +00001409 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1410 const auto result = sendToStatsd(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001411 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001412 , path
1413 , direction
1414 , framesPerBurst
1415 , bufferSizeInFrames
1416 , bufferCapacityInFrames
1417 , channelCount
1418 , totalFramesTransferred
1419 , perfModeRequested
1420 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001421 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001422 , xrunCount
1423 , bf_serialized
1424 , formatApp
1425 , formatDevice
1426 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001427 , sampleRate
1428 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001429 , sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001430 , formatHardware
1431 , channelCountHardware
1432 , sampleRateHardware
Robert Wue51e4df2023-02-15 21:46:12 +00001433 , uid
jiabin92c9a522021-02-12 22:37:42 +00001434 );
1435 std::stringstream ss;
1436 ss << "result:" << result;
1437 const auto fieldsStr = printFields(AAudioStreamFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001438 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001439 , path
1440 , direction
1441 , framesPerBurst
1442 , bufferSizeInFrames
1443 , bufferCapacityInFrames
1444 , channelCount
1445 , totalFramesTransferred
1446 , perfModeRequested
1447 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001448 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001449 , xrunCount
1450 , serializedDeviceTypes.c_str()
1451 , formatApp
1452 , formatDevice
1453 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001454 , sampleRate
1455 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001456 , sharingModeRequested
Robert Wuf49223c2023-01-26 23:07:02 +00001457 , formatHardware
1458 , channelCountHardware
1459 , sampleRateHardware
Robert Wue51e4df2023-02-15 21:46:12 +00001460 , uid
jiabin92c9a522021-02-12 22:37:42 +00001461 );
1462 ss << " " << fieldsStr;
1463 std::string str = ss.str();
1464 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001465 mAudioAnalytics.mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001466 }
jiabin515eb092020-11-18 17:55:52 -08001467}
1468
Andy Hungf4eaa462022-03-09 21:53:09 -08001469// Create new state, typically occurs after an AudioFlinger ctor event.
1470void AudioAnalytics::newState()
1471{
1472 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1473 *mAnalyticsState.get()));
1474 // Note: get returns shared_ptr temp, whose lifetime is extended
1475 // to end of full expression.
1476 mAnalyticsState->clear(); // TODO: filter the analytics state.
1477 // Perhaps report this.
1478
1479 // Set up a timer to expire the previous audio state to save space.
1480 // Use the transaction log size as a cookie to see if it is the
1481 // same as before. A benign race is possible where a state is cleared early.
1482 const size_t size = mPreviousAnalyticsState->transactionLog().size();
1483 mTimedAction.postIn(
1484 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1485 if (mPreviousAnalyticsState->transactionLog().size() == size) {
1486 ALOGD("expiring previous audio state after %d seconds.",
1487 PREVIOUS_STATE_EXPIRE_SEC);
1488 mPreviousAnalyticsState->clear(); // removes data from the state.
1489 }
1490 });
1491}
1492
1493void AudioAnalytics::Health::onAudioServerStart(Module module,
1494 const std::shared_ptr<const android::mediametrics::Item> &item)
1495{
1496 const auto nowTime = std::chrono::system_clock::now();
1497 if (module == Module::AUDIOFLINGER) {
1498 {
1499 std::lock_guard lg(mLock);
1500 // reset state on AudioFlinger construction.
1501 // AudioPolicy is created after AudioFlinger.
1502 mAudioFlingerCtorTime = nowTime;
1503 mSimpleLog.log("AudioFlinger ctor");
1504 }
1505 mAudioAnalytics.newState();
1506 return;
1507 }
1508 if (module == Module::AUDIOPOLICY) {
1509 // A start event occurs when audioserver
1510 //
1511 // (1) Starts the first time
1512 // (2) Restarts because of the TimeCheck watchdog
1513 // (3) Restarts not because of the TimeCheck watchdog.
1514 int64_t executionTimeNs = 0;
1515 (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1516 const float loadTimeMs = executionTimeNs * 1e-6f;
1517 std::lock_guard lg(mLock);
1518 const int64_t restarts = mStartCount;
1519 if (mStopCount == mStartCount) {
1520 mAudioPolicyCtorTime = nowTime;
1521 ++mStartCount;
1522 if (mStopCount == 0) {
1523 // (1) First time initialization.
1524 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1525 __func__, item->getKey().c_str(), loadTimeMs);
1526 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1527 } else {
1528 // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
1529 const float restartMs =
1530 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1531 mAudioFlingerCtorTime - mStopTime).count();
1532 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1533 "restarts:%lld restartMs:%f loadTimeMs:%f",
1534 __func__, item->getKey().c_str(),
1535 (long long)restarts, restartMs, loadTimeMs);
1536 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1537 (long long)restarts, restartMs, loadTimeMs);
1538 }
1539 } else {
1540 // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1541 // However we can estimate the uptime from the delta time from previous ctor.
1542 const float uptimeMs =
1543 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1544 nowTime - mAudioFlingerCtorTime).count();
1545 mStopCount = mStartCount;
1546 mAudioPolicyCtorTime = nowTime;
1547 ++mStartCount;
1548
1549 ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1550 "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1551 __func__, item->getKey().c_str(),
1552 (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1553 mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1554 "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1555 (long long)restarts, uptimeMs, loadTimeMs);
1556 }
1557 }
1558}
1559
1560void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1561 const std::shared_ptr<const android::mediametrics::Item> &item)
1562{
1563 std::string moduleName = getModuleName(module);
1564 int64_t methodCode{};
1565 std::string methodName;
1566 (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1567 (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1568
1569 std::lock_guard lg(mLock);
1570 if (mStopCount >= mStartCount) {
1571 ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1572 "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1573 __func__, item->getKey().c_str(), moduleName.c_str(),
1574 methodName.c_str(), (long long)methodCode,
1575 (long long)mStopCount, (long long)mStartCount);
1576 return;
1577 }
1578
1579 const int64_t restarts = mStartCount - 1;
1580 ++mStopCount;
1581 mStopTime = std::chrono::system_clock::now();
1582 const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1583 mStopTime - mAudioFlingerCtorTime).count();
1584 ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1585 __func__, item->getKey().c_str(), moduleName.c_str(),
1586 methodName.c_str(), (long long)methodCode,
1587 (long long)restarts, uptimeMs);
1588 mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1589 moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1590 (long long)restarts, uptimeMs);
1591}
1592
1593std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1594 int32_t lines, const char *prefix) const
1595{
1596 std::lock_guard lg(mLock);
1597 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1598 size_t n = std::count(s.begin(), s.end(), '\n');
1599 return { s, n };
1600}
1601
Andy Hung05874e82022-08-17 17:27:32 -07001602// Classifies the setting event for statsd (use generated statsd enums.proto constants).
1603static int32_t classifySettingEvent(bool isSetAlready, bool withinBoot) {
1604 if (isSetAlready) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001605 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_NORMAL;
Andy Hung05874e82022-08-17 17:27:32 -07001606 }
1607 if (withinBoot) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001608 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_BOOT;
Andy Hung05874e82022-08-17 17:27:32 -07001609 }
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001610 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_FIRST;
Andy Hung05874e82022-08-17 17:27:32 -07001611}
1612
Andy Hunge0d43b42022-08-18 19:20:48 -07001613void AudioAnalytics::Spatializer::onEvent(
1614 const std::shared_ptr<const android::mediametrics::Item> &item)
1615{
1616 const auto key = item->getKey();
1617
1618 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1619
1620 const std::string suffix =
1621 key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1622
1623 std::string eventStr; // optional - find the actual event string.
1624 (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1625
1626 const size_t delim = suffix.find('.'); // note could use split.
1627 if (delim == suffix.npos) {
1628 // on create with suffix == "0" for the first spatializer effect.
1629
1630 std::string headTrackingModes;
1631 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1632
1633 std::string levels;
1634 (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1635
1636 std::string modes;
1637 (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1638
Andy Hung05874e82022-08-17 17:27:32 -07001639 std::string channelMasks;
1640 (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASKS, &channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001641
1642 LOG(LOG_LEVEL) << "key:" << key
1643 << " headTrackingModes:" << headTrackingModes
1644 << " levels:" << levels
1645 << " modes:" << modes
Andy Hung05874e82022-08-17 17:27:32 -07001646 << " channelMasks:" << channelMasks
Andy Hunge0d43b42022-08-18 19:20:48 -07001647 ;
1648
1649 const std::vector<int32_t> headTrackingModesVector =
1650 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1651 const std::vector<int32_t> levelsVector =
1652 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1653 const std::vector<int32_t> modesVector =
1654 types::vectorFromMap(modes, types::getSpatializerModeMap());
Andy Hung05874e82022-08-17 17:27:32 -07001655 const std::vector<int64_t> channelMasksVector =
1656 types::channelMaskVectorFromString(channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001657
Andy Hung05874e82022-08-17 17:27:32 -07001658 const auto [ result, str ] = sendToStatsd(SpatializerCapabilitiesFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001659 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001660 , headTrackingModesVector
1661 , levelsVector
1662 , modesVector
1663 , channelMasksVector
1664 );
1665
1666 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001667 stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001668
1669 std::lock_guard lg(mLock);
Andy Hung05874e82022-08-17 17:27:32 -07001670 if (mFirstCreateTimeNs == 0) {
1671 // Only update the create time once to prevent audioserver restart
1672 // from looking like a boot.
1673 mFirstCreateTimeNs = item->getTimestamp();
1674 }
Andy Hunge0d43b42022-08-18 19:20:48 -07001675 mSimpleLog.log("%s suffix: %s item: %s",
1676 __func__, suffix.c_str(), item->toString().c_str());
1677 } else {
1678 std::string subtype = suffix.substr(0, delim);
1679 if (subtype != "device") return; // not a device.
1680
Andy Hung05874e82022-08-17 17:27:32 -07001681 const std::string deviceType = suffix.substr(std::size("device.") - 1);
Andy Hunge0d43b42022-08-18 19:20:48 -07001682
Andy Hung05874e82022-08-17 17:27:32 -07001683 const int32_t deviceTypeStatsd =
1684 types::lookup<types::AUDIO_DEVICE_INFO_TYPE, int32_t>(deviceType);
1685
1686 std::string address;
1687 (void)item->get(AMEDIAMETRICS_PROP_ADDRESS, &address);
Andy Hunge0d43b42022-08-18 19:20:48 -07001688 std::string enabled;
1689 (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1690 std::string hasHeadTracker;
1691 (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1692 std::string headTrackerEnabled;
1693 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1694
1695 std::lock_guard lg(mLock);
1696
1697 // Validate from our cached state
Andy Hung05874e82022-08-17 17:27:32 -07001698
1699 // Our deviceKey takes the device type and appends the address if any.
1700 // This distinguishes different wireless devices for the purposes of tracking.
1701 std::string deviceKey(deviceType);
1702 deviceKey.append("_").append(address);
1703 DeviceState& deviceState = mDeviceStateMap[deviceKey];
1704
1705 // check whether the settings event is within a certain time of spatializer creation.
1706 const bool withinBoot =
1707 item->getTimestamp() - mFirstCreateTimeNs < kBootDurationThreshold;
Andy Hunge0d43b42022-08-18 19:20:48 -07001708
1709 if (!enabled.empty()) {
1710 if (enabled != deviceState.enabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001711 const int32_t settingEventStatsd =
1712 classifySettingEvent(!deviceState.enabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001713 deviceState.enabled = enabled;
1714 const bool enabledStatsd = enabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001715 const auto [ result, str ] = sendToStatsd(SpatializerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001716 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001717 , deviceTypeStatsd
1718 , settingEventStatsd
1719 , enabledStatsd
1720 );
1721 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001722 stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001723 }
1724 }
1725 if (!hasHeadTracker.empty()) {
1726 if (hasHeadTracker != deviceState.hasHeadTracker) {
Andy Hung05874e82022-08-17 17:27:32 -07001727 const int32_t settingEventStatsd =
1728 classifySettingEvent(!deviceState.hasHeadTracker.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001729 deviceState.hasHeadTracker = hasHeadTracker;
1730 const bool supportedStatsd = hasHeadTracker == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001731 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceSupportedFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001732 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001733 , deviceTypeStatsd
1734 , settingEventStatsd
1735 , supportedStatsd
1736 );
1737 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001738 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001739 }
1740 }
1741 if (!headTrackerEnabled.empty()) {
1742 if (headTrackerEnabled != deviceState.headTrackerEnabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001743 const int32_t settingEventStatsd =
1744 classifySettingEvent(!deviceState.headTrackerEnabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001745 deviceState.headTrackerEnabled = headTrackerEnabled;
1746 const bool enabledStatsd = headTrackerEnabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001747 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001748 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001749 , deviceTypeStatsd
1750 , settingEventStatsd
1751 , enabledStatsd
1752 );
1753 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001754 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001755 }
1756 }
Andy Hung05874e82022-08-17 17:27:32 -07001757 mSimpleLog.log("%s deviceKey: %s item: %s",
1758 __func__, deviceKey.c_str(), item->toString().c_str());
Andy Hunge0d43b42022-08-18 19:20:48 -07001759 }
1760}
1761
1762std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1763 int32_t lines, const char *prefix) const
1764{
1765 std::lock_guard lg(mLock);
1766 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1767 size_t n = std::count(s.begin(), s.end(), '\n');
1768 return { s, n };
1769}
Andy Hungf4eaa462022-03-09 21:53:09 -08001770
Robert Wu38439732022-11-02 23:16:04 +00001771void AudioAnalytics::MidiLogging::onEvent(
1772 const std::shared_ptr<const android::mediametrics::Item> &item) const {
1773 const std::string& key = item->getKey();
1774
1775 const auto uid = item->getUid();
1776
1777 int32_t deviceId = -1;
1778 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1779 key, AMEDIAMETRICS_PROP_DEVICEID, &deviceId);
1780
1781 int32_t inputPortCount = -1;
1782 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1783 key, AMEDIAMETRICS_PROP_INPUTPORTCOUNT, &inputPortCount);
1784
1785 int32_t outputPortCount = -1;
1786 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1787 key, AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT, &outputPortCount);
1788
1789 int32_t hardwareType = -1;
1790 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1791 key, AMEDIAMETRICS_PROP_HARDWARETYPE, &hardwareType);
1792
1793 std::string isSharedString;
1794 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1795 key, AMEDIAMETRICS_PROP_ISSHARED, &isSharedString);
1796 const bool isShared = (isSharedString == "true");
1797
1798 std::string supportsMidiUmpString;
1799 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1800 key, AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP, &supportsMidiUmpString);
1801 const bool supportsMidiUmp = (supportsMidiUmpString == "true");
1802
1803 std::string usingAlsaString;
1804 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1805 key, AMEDIAMETRICS_PROP_USINGALSA, &usingAlsaString);
1806 const bool usingAlsa = (usingAlsaString == "true");
1807
1808 int64_t durationNs = -1;
1809 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1810 key, AMEDIAMETRICS_PROP_DURATIONNS, &durationNs);
1811
1812 int32_t openedCount = -1;
1813 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1814 key, AMEDIAMETRICS_PROP_OPENEDCOUNT, &openedCount);
1815
1816 int32_t closedCount = -1;
1817 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1818 key, AMEDIAMETRICS_PROP_CLOSEDCOUNT, &closedCount);
1819
1820 std::string deviceDisconnectedString;
1821 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1822 key, AMEDIAMETRICS_PROP_DEVICEDISCONNECTED, &deviceDisconnectedString);
1823 const bool deviceDisconnected = (deviceDisconnectedString == "true");
1824
1825 int32_t totalInputBytes = -1;
1826 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1827 key, AMEDIAMETRICS_PROP_TOTALINPUTBYTES, &totalInputBytes);
1828
1829 int32_t totalOutputBytes = -1;
1830 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1831 key, AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES, &totalOutputBytes);
1832
1833 LOG(LOG_LEVEL) << "key:" << key
1834 << " uid:" << uid
1835 << " id:" << deviceId
1836 << " input_port_count:" << inputPortCount
1837 << " output_port_count:" << outputPortCount
1838 << " device_type:" << hardwareType
1839 << " is_shared:" << isSharedString
1840 << " supports_ump:" << supportsMidiUmpString
1841 << " using_alsa:" << usingAlsaString
1842 << " duration_opened_ms:" << durationNs
1843 << " opened_count:" << openedCount
1844 << " closed_count:" << closedCount
1845 << " device_disconnected:" << deviceDisconnectedString
1846 << " total_input_bytes:" << totalInputBytes
1847 << " total_output_bytes:" << totalOutputBytes;
1848
1849 if (mAudioAnalytics.mDeliverStatistics) {
1850 const auto result = sendToStatsd(
1851 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1852 , uid
1853 , deviceId
1854 , inputPortCount
1855 , outputPortCount
1856 , hardwareType
1857 , isShared
1858 , supportsMidiUmp
1859 , usingAlsa
1860 , durationNs
1861 , openedCount
1862 , closedCount
1863 , deviceDisconnected
1864 , totalInputBytes
1865 , totalOutputBytes);
1866 std::stringstream ss;
1867 ss << "result:" << result;
1868 const auto fieldsStr = printFields(MidiDeviceCloseFields,
1869 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1870 , uid
1871 , deviceId
1872 , inputPortCount
1873 , outputPortCount
1874 , hardwareType
1875 , isShared
1876 , supportsMidiUmp
1877 , usingAlsa
1878 , durationNs
1879 , openedCount
1880 , closedCount
1881 , deviceDisconnected
1882 , totalInputBytes
1883 , totalOutputBytes);
1884 ss << " " << fieldsStr;
1885 std::string str = ss.str();
1886 ALOGV("%s: statsd %s", __func__, str.c_str());
1887 mAudioAnalytics.mStatsdLog->log(
1888 stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED, str);
1889 }
1890}
1891
Andy Hung76adef72022-09-14 17:24:19 -07001892// This method currently suppresses the name.
1893std::string AudioAnalytics::getDeviceNamesFromOutputDevices(std::string_view devices) const {
1894 std::string deviceNames;
1895 if (stringutils::hasBluetoothOutputDevice(devices)) {
1896 deviceNames = SUPPRESSED;
1897#if 0 // TODO(b/161554630) sanitize name
1898 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1899 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
1900 // Remove | if present
1901 stringutils::replace(deviceNames, "|", '?');
1902 if (deviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
1903 deviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
1904 }
1905#endif
1906 }
1907 return deviceNames;
1908}
1909
Andy Hung3ab1b322020-05-18 10:47:31 -07001910} // namespace android::mediametrics