blob: 7af6c413fee77262b99fd50872c678efbeb2f32a [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",
jiabin92c9a522021-02-12 22:37:42 +0000241};
242
Andy Hung05874e82022-08-17 17:27:32 -0700243static constexpr const char * HeadTrackerDeviceEnabledFields[] {
244 "mediametrics_headtrackerdeviceenabled_reported",
245 "type",
246 "event",
247 "enabled",
248};
249
250static constexpr const char * HeadTrackerDeviceSupportedFields[] {
251 "mediametrics_headtrackerdevicesupported_reported",
252 "type",
253 "event",
254 "supported",
255};
256
257static constexpr const char * SpatializerCapabilitiesFields[] {
258 "mediametrics_spatializer_reported",
259 "head_tracking_modes",
260 "spatializer_levels",
261 "spatializer_modes",
262 "channel_masks",
263};
264
265static constexpr const char * SpatializerDeviceEnabledFields[] {
266 "mediametrics_spatializerdeviceenabled_reported",
267 "type",
268 "event",
269 "enabled",
270};
271
Robert Wu38439732022-11-02 23:16:04 +0000272static constexpr const char * const MidiDeviceCloseFields[] {
273 "mediametrics_midi_device_close_reported",
274 "uid",
275 "midi_device_id",
276 "input_port_count",
277 "output_port_count",
278 "device_type",
279 "is_shared",
280 "supports_ump",
281 "using_alsa",
282 "duration_ns",
283 "opened_count",
284 "closed_count",
285 "device_disconnected",
286 "total_input_bytes",
287 "total_output_bytes",
288};
289
jiabin92c9a522021-02-12 22:37:42 +0000290/**
291 * printFields is a helper method that prints the fields and corresponding values
292 * in a human readable style.
293 */
294template <size_t N, typename ...Types>
295std::string printFields(const char * const (& fields)[N], Types ... args)
296{
297 std::stringstream ss;
298 ss << " { ";
299 stringutils::fieldPrint(ss, fields, args...);
300 ss << "}";
301 return ss.str();
302}
303
304/**
305 * sendToStatsd is a helper method that sends the arguments to statsd
306 */
307template <typename ...Types>
308int sendToStatsd(Types ... args)
309{
310 int result = 0;
311
312#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000313 result = stats::media_metrics::stats_write(args...);
jiabin92c9a522021-02-12 22:37:42 +0000314#endif
315 return result;
316}
jiabin515eb092020-11-18 17:55:52 -0800317
Andy Hunga629bd12020-06-05 16:03:53 -0700318/**
319 * sendToStatsd is a helper method that sends the arguments to statsd
320 * and returns a pair { result, summary_string }.
321 */
322template <size_t N, typename ...Types>
323std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
324{
325 int result = 0;
326 std::stringstream ss;
327
328#ifdef STATSD_ENABLE
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000329 result = stats::media_metrics::stats_write(args...);
Andy Hunga629bd12020-06-05 16:03:53 -0700330 ss << "result:" << result;
331#endif
332 ss << " { ";
333 stringutils::fieldPrint(ss, fields, args...);
334 ss << "}";
335 return { result, ss.str() };
336}
Andy Hung06f3aba2019-12-03 16:36:42 -0800337
Andy Hung5be90c82021-03-30 14:30:20 -0700338AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700339 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700340 , mStatsdLog(statsdLog)
341 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800342{
Andy Hunga629bd12020-06-05 16:03:53 -0700343 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800344 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800345
346 // Add action to save AnalyticsState if audioserver is restarted.
Andy Hungf4eaa462022-03-09 21:53:09 -0800347 // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
348 // as well as TimeCheck events.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800349 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800350 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
351 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800352 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800353 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungf4eaa462022-03-09 21:53:09 -0800354 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
355 }));
356 mActions.addAction(
357 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
358 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
359 std::make_shared<AnalyticsActions::Function>(
360 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
361 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
362 }));
363 mActions.addAction(
364 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
365 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
366 std::make_shared<AnalyticsActions::Function>(
367 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
368 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
369 }));
370 mActions.addAction(
371 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
372 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
373 std::make_shared<AnalyticsActions::Function>(
374 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
375 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
Andy Hungea186fa2020-01-09 18:13:15 -0800376 }));
377
jiabin97247ea2021-04-07 00:33:38 +0000378 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800379 mActions.addAction(
380 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
381 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
382 std::make_shared<AnalyticsActions::Function>(
383 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
384 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
385 }));
386
jiabin97247ea2021-04-07 00:33:38 +0000387 // Handle legacy aaudio capture stream statistics
388 mActions.addAction(
389 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
390 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
391 std::make_shared<AnalyticsActions::Function>(
392 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
393 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
394 }));
395
jiabin515eb092020-11-18 17:55:52 -0800396 // Handle mmap aaudio stream statistics
397 mActions.addAction(
398 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
399 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
400 std::make_shared<AnalyticsActions::Function>(
401 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
402 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
403 }));
404
Andy Hungea840382020-05-05 21:50:17 -0700405 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800406 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700407 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
408 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800409 std::make_shared<AnalyticsActions::Function>(
410 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700411 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800412 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700413
414 // Handle device use thread statistics
415 mActions.addAction(
416 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
417 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
418 std::make_shared<AnalyticsActions::Function>(
419 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700420 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700421 }));
422
423 // Handle device use track statistics
424 mActions.addAction(
425 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
426 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
427 std::make_shared<AnalyticsActions::Function>(
428 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700429 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700430 }));
431
Andy Hungea840382020-05-05 21:50:17 -0700432
433 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700434
435 // We track connections (not disconnections) for the time to connect.
436 // TODO: consider BT requests in their A2dp service
437 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
438 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
439 // AudioDeviceBroker.postA2dpActiveDeviceChange
440 mActions.addAction(
441 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700442 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700443 std::make_shared<AnalyticsActions::Function>(
444 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
445 mDeviceConnection.a2dpConnected(item);
446 }));
447 // If audio is active, we expect to see a createAudioPatch after the device is connected.
448 mActions.addAction(
449 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
450 std::string("createAudioPatch"),
451 std::make_shared<AnalyticsActions::Function>(
452 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
453 mDeviceConnection.createPatch(item);
454 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800455
Andy Hungea840382020-05-05 21:50:17 -0700456 // Called from BT service
457 mActions.addAction(
458 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
459 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
460 "." AMEDIAMETRICS_PROP_STATE,
461 "connected",
462 std::make_shared<AnalyticsActions::Function>(
463 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
464 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
465 }));
466
Joey Poomarin52989982020-03-05 17:40:49 +0800467 // Handle power usage
468 mActions.addAction(
469 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
470 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
471 std::make_shared<AnalyticsActions::Function>(
472 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
473 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
474 }));
475
476 mActions.addAction(
477 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
478 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
479 std::make_shared<AnalyticsActions::Function>(
480 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
481 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
482 }));
483
484 mActions.addAction(
485 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
486 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
487 std::make_shared<AnalyticsActions::Function>(
488 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
489 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
490 mAudioPowerUsage.checkMode(item);
491 }));
492
493 mActions.addAction(
494 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
495 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
496 std::make_shared<AnalyticsActions::Function>(
497 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
498 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
499 mAudioPowerUsage.checkVoiceVolume(item);
500 }));
501
502 mActions.addAction(
503 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
504 std::string("createAudioPatch"),
505 std::make_shared<AnalyticsActions::Function>(
506 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
507 mAudioPowerUsage.checkCreatePatch(item);
508 }));
Andy Hunge0d43b42022-08-18 19:20:48 -0700509
510 // Handle Spatializer - these keys are prefixed by "audio.spatializer."
511 mActions.addAction(
512 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
513 std::monostate{}, /* match any event */
514 std::make_shared<AnalyticsActions::Function>(
515 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
516 mSpatializer.onEvent(item);
517 }));
Robert Wu38439732022-11-02 23:16:04 +0000518
519 // Handle MIDI
520 mActions.addAction(
521 AMEDIAMETRICS_KEY_AUDIO_MIDI "." AMEDIAMETRICS_PROP_EVENT,
522 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED),
523 std::make_shared<AnalyticsActions::Function>(
524 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
525 mMidiLogging.onEvent(item);
526 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800527}
528
529AudioAnalytics::~AudioAnalytics()
530{
531 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700532 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800533}
534
535status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800536 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800537{
Andy Hungea186fa2020-01-09 18:13:15 -0800538 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800539 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800540
541 // Status is selectively authenticated.
542 processStatus(item);
543
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800544 if (status != NO_ERROR) return status; // may not be permitted.
545
546 // Only if the item was successfully submitted (permission)
547 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800548 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800549 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800550}
551
Andy Hung709b91e2020-04-04 14:23:36 -0700552std::pair<std::string, int32_t> AudioAnalytics::dump(
553 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800554{
555 std::stringstream ss;
556 int32_t ll = lines;
557
558 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700559 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700560 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800561 ll -= l;
562 }
563 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800564 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800565 --ll;
566 }
567 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700568 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700569 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800570 ll -= l;
571 }
Joey Poomarin52989982020-03-05 17:40:49 +0800572
573 if (ll > 0 && prefix == nullptr) {
574 auto [s, l] = mAudioPowerUsage.dump(ll);
575 ss << s;
576 ll -= l;
577 }
Andy Hunga629bd12020-06-05 16:03:53 -0700578
Andy Hung06f3aba2019-12-03 16:36:42 -0800579 return { ss.str(), lines - ll };
580}
581
Andy Hung73dc2f92021-12-07 21:50:04 -0800582void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800583{
584 auto actions = mActions.getActionsForItem(item); // internally locked.
585 // Execute actions with no lock held.
586 for (const auto& action : actions) {
587 (*action)(item);
588 }
589}
590
Andy Hung73dc2f92021-12-07 21:50:04 -0800591void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
592{
593 int32_t status;
594 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
595
596 // Any record with a status will automatically be added to a heat map.
597 // Standard information.
598 const auto key = item->getKey();
599 const auto uid = item->getUid();
600
601 // from audio.track.10 -> prefix = audio.track, suffix = 10
602 // from audio.track.error -> prefix = audio.track, suffix = error
603 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
604
605 std::string message;
606 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
607
608 int32_t subCode = 0; // not used
609 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
610
611 std::string eventStr; // optional
612 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
613
614 const std::string statusString = extendedStatusToStatusString(status);
615
616 // Add to the heat map - we automatically track every item's status to see
617 // the types of errors and the frequency of errors.
618 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800619
Andy Hung44326582022-01-11 17:27:09 -0800620 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
621 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
622 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
623}
624
625bool AudioAnalytics::reportAudioRecordStatus(
626 const std::shared_ptr<const mediametrics::Item>& item,
627 const std::string& key, const std::string& eventStr,
628 const std::string& statusString, uid_t uid, const std::string& message,
629 int32_t subCode) const
630{
Andy Hungb8918b52021-12-14 22:15:40 -0800631 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800632 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
633 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
634 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
635
636 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000637 const int32_t event = stats::media_metrics::
Andy Hung44326582022-01-11 17:27:09 -0800638 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
639
640 // The following fields should all be present in a create event.
641 std::string flagsStr;
642 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
643 "%s: %s missing %s field", __func__,
644 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
645 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
646
647 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
648
649 std::string sourceStr;
650 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
651 "%s: %s missing %s field",
652 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
653 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
654
655 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
656
657 std::string encodingStr;
658 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
659 "%s: %s missing %s field",
660 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
661 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
662
663 int32_t channelMask = 0;
664 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
665 "%s: %s missing %s field",
666 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
667 int32_t frameCount = 0;
668 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
669 "%s: %s missing %s field",
670 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
671 int32_t sampleRate = 0;
672 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
673 "%s: %s missing %s field",
674 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
675
676 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000677 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
Andy Hung44326582022-01-11 17:27:09 -0800678 , atom_status
679 , message.c_str()
680 , subCode
681 , uid
682 , event
683 , flags
684 , source
685 , encoding
686 , (int64_t)channelMask
687 , frameCount
688 , sampleRate
689 );
690 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000691 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800692 return true;
693 }
694 return false;
695}
696
697bool AudioAnalytics::reportAudioTrackStatus(
698 const std::shared_ptr<const mediametrics::Item>& item,
699 const std::string& key, const std::string& eventStr,
700 const std::string& statusString, uid_t uid, const std::string& message,
701 int32_t subCode) const
702{
703 // Note that the prefixes often end with a '.' so we use startsWith.
704 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
705 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800706 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
707
708 // currently we only send create status events.
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000709 const int32_t event = stats::media_metrics::
Andy Hungcb40b982022-01-31 20:08:25 -0800710 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800711
712 // The following fields should all be present in a create event.
713 std::string flagsStr;
714 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
715 "%s: %s missing %s field",
716 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
717 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
718
719 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
720
721 std::string contentTypeStr;
722 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
723 "%s: %s missing %s field",
724 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
725 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
726
727 std::string usageStr;
728 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
729 "%s: %s missing %s field",
730 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
731 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
732
733 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
734
735 std::string encodingStr;
736 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
737 "%s: %s missing %s field",
738 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
739 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
740
741 int32_t channelMask = 0;
742 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
743 "%s: %s missing %s field",
744 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
745 int32_t frameCount = 0;
746 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
747 "%s: %s missing %s field",
748 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
749 int32_t sampleRate = 0;
750 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
751 "%s: %s missing %s field",
752 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
753 double speed = 0.f; // default is 1.f
754 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
755 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800756 __func__,
757 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800758 double pitch = 0.f; // default is 1.f
759 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
760 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800761 __func__,
762 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800763 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000764 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
Andy Hungb8918b52021-12-14 22:15:40 -0800765 , atom_status
766 , message.c_str()
767 , subCode
768 , uid
769 , event
770 , flags
771 , contentType
772 , usage
773 , encoding
774 , (int64_t)channelMask
775 , frameCount
776 , sampleRate
777 , (float)speed
778 , (float)pitch
779 );
780 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000781 mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800782 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800783 }
Andy Hung44326582022-01-11 17:27:09 -0800784 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800785}
786
Andy Hungea186fa2020-01-09 18:13:15 -0800787// HELPER METHODS
788
789std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
790{
791 int32_t threadId_int32{};
792 if (mAnalyticsState->timeMachine().get(
793 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
794 return {};
795 }
796 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
797}
798
Andy Hungce9b6632020-04-28 20:15:17 -0700799// DeviceUse helper class.
800void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700801 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700802 const std::string& key = item->getKey();
803 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700804 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
805 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
806 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700807 - 1);
808 // deliver statistics
809 int64_t deviceTimeNs = 0;
810 mAudioAnalytics.mAnalyticsState->timeMachine().get(
811 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
812 std::string encoding;
813 mAudioAnalytics.mAnalyticsState->timeMachine().get(
814 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
815 int32_t frameCount = 0;
816 mAudioAnalytics.mAnalyticsState->timeMachine().get(
817 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
818 int32_t intervalCount = 0;
819 mAudioAnalytics.mAnalyticsState->timeMachine().get(
820 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hungce9b6632020-04-28 20:15:17 -0700821 int32_t sampleRate = 0;
822 mAudioAnalytics.mAnalyticsState->timeMachine().get(
823 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700824 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700825 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700826 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700827
Andy Hungea840382020-05-05 21:50:17 -0700828 switch (itemType) {
829 case RECORD: {
Andy Hung76adef72022-09-14 17:24:19 -0700830 std::string inputDevicePairs;
831 mAudioAnalytics.mAnalyticsState->timeMachine().get(
832 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
833
834 const auto [ inputDeviceStatsd, inputDevices ] =
835 stringutils::parseInputDevicePairs(inputDevicePairs);
836 const std::string inputDeviceNames; // not filled currently.
837
Andy Hungea840382020-05-05 21:50:17 -0700838 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700839 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
840 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700841
Andy Hungea840382020-05-05 21:50:17 -0700842 std::string packageName;
843 int64_t versionCode = 0;
844 int32_t uid = -1;
845 mAudioAnalytics.mAnalyticsState->timeMachine().get(
846 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
847 if (uid != -1) {
848 std::tie(packageName, versionCode) =
849 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
850 }
851
852 int32_t selectedDeviceId = 0;
853 mAudioAnalytics.mAnalyticsState->timeMachine().get(
854 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
855 std::string source;
856 mAudioAnalytics.mAnalyticsState->timeMachine().get(
857 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800858 // Android S
859 std::string logSessionId;
860 mAudioAnalytics.mAnalyticsState->timeMachine().get(
861 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700862
Andy Hung1ea842e2020-05-18 10:47:31 -0700863 const auto callerNameForStats =
864 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
865 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
866 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
867 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800868 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700869 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700870
Andy Hunga629bd12020-06-05 16:03:53 -0700871 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700872 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700873 << " inputDevices:" << inputDevices << "(" << inputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -0700874 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700875 << " deviceTimeNs:" << deviceTimeNs
876 << " encoding:" << encoding << "(" << encodingForStats
877 << ") frameCount:" << frameCount
878 << " intervalCount:" << intervalCount
879 << " sampleRate:" << sampleRate
880 << " flags:" << flags << "(" << flagsForStats
881 << ") packageName:" << packageName
882 << " selectedDeviceId:" << selectedDeviceId
883 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800884 << ") source:" << source << "(" << sourceForStats
885 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
886 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700887 if (clientCalled // only log if client app called AudioRecord.
888 && mAudioAnalytics.mDeliverStatistics) {
889 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000890 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700891 , ENUM_EXTRACT(inputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -0700892 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700893 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700894 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700895 , frameCount
896 , intervalCount
897 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700898 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700899
900 , packageName.c_str()
901 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700902 , ENUM_EXTRACT(callerNameForStats)
903 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800904 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700905 );
Andy Hunga629bd12020-06-05 16:03:53 -0700906 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700907 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000908 stats::media_metrics::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700909 }
Andy Hungea840382020-05-05 21:50:17 -0700910 } break;
911 case THREAD: {
912 std::string type;
913 mAudioAnalytics.mAnalyticsState->timeMachine().get(
914 key, AMEDIAMETRICS_PROP_TYPE, &type);
915 int32_t underrun = 0; // zero for record types
916 mAudioAnalytics.mAnalyticsState->timeMachine().get(
917 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700918
919 const bool isInput = types::isInputThreadType(type);
Andy Hung76adef72022-09-14 17:24:19 -0700920
921 // get device information
922 std::string devicePairs;
923 std::string deviceStatsd;
924 std::string devices;
925 std::string deviceNames;
926 if (isInput) {
927 // Note we get the "last" device which is the one associated with group.
928 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_INPUTDEVICES,
929 &devicePairs);
930 std::tie(deviceStatsd, devices) = stringutils::parseInputDevicePairs(devicePairs);
931 } else {
932 // Note we get the "last" device which is the one associated with group.
933 item->get(AMEDIAMETRICS_PROP_PREFIX_LAST AMEDIAMETRICS_PROP_OUTPUTDEVICES,
934 &devicePairs);
935 std::tie(deviceStatsd, devices) = stringutils::parseOutputDevicePairs(devicePairs);
936 deviceNames = mAudioAnalytics.getDeviceNamesFromOutputDevices(devices);
937 }
938
Andy Hung1ea842e2020-05-18 10:47:31 -0700939 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
940 const auto flagsForStats =
941 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
942 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
943 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
944
Andy Hung76adef72022-09-14 17:24:19 -0700945 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700946 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -0700947 << " devices:" << devices << "(" << deviceStatsd
948 << ") deviceNames:" << deviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700949 << " deviceTimeNs:" << deviceTimeNs
950 << " encoding:" << encoding << "(" << encodingForStats
951 << ") frameCount:" << frameCount
952 << " intervalCount:" << intervalCount
953 << " sampleRate:" << sampleRate
954 << " underrun:" << underrun
955 << " flags:" << flags << "(" << flagsForStats
956 << ") type:" << type << "(" << typeForStats
957 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700958 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700959 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000960 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -0700961 , ENUM_EXTRACT(deviceStatsd)
962 , deviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700963 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700964 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700965 , frameCount
966 , intervalCount
967 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700968 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700969 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700970 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700971 );
Andy Hunga629bd12020-06-05 16:03:53 -0700972 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700973 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +0000974 stats::media_metrics::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700975 }
Andy Hungea840382020-05-05 21:50:17 -0700976 } break;
977 case TRACK: {
Andy Hung76adef72022-09-14 17:24:19 -0700978 std::string outputDevicePairs;
979 mAudioAnalytics.mAnalyticsState->timeMachine().get(
980 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
981
982 const auto [ outputDeviceStatsd, outputDevices ] =
983 stringutils::parseOutputDevicePairs(outputDevicePairs);
984 const std::string outputDeviceNames =
985 mAudioAnalytics.getDeviceNamesFromOutputDevices(outputDevices);
986
Andy Hungce9b6632020-04-28 20:15:17 -0700987 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700988 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
989 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
990
Andy Hungce9b6632020-04-28 20:15:17 -0700991 std::string contentType;
992 mAudioAnalytics.mAnalyticsState->timeMachine().get(
993 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
994 double deviceLatencyMs = 0.;
995 mAudioAnalytics.mAnalyticsState->timeMachine().get(
996 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
997 double deviceStartupMs = 0.;
998 mAudioAnalytics.mAnalyticsState->timeMachine().get(
999 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
1000 double deviceVolume = 0.;
1001 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1002 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
1003 std::string packageName;
1004 int64_t versionCode = 0;
1005 int32_t uid = -1;
1006 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1007 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
1008 if (uid != -1) {
1009 std::tie(packageName, versionCode) =
1010 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
1011 }
1012 double playbackPitch = 0.;
1013 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1014 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
1015 double playbackSpeed = 0.;
1016 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1017 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
1018 int32_t selectedDeviceId = 0;
1019 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1020 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -07001021 std::string streamType;
1022 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1023 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001024 std::string traits;
1025 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1026 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -07001027 int32_t underrun = 0;
1028 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1029 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -07001030 std::string usage;
1031 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1032 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001033 // Android S
1034 std::string logSessionId;
1035 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1036 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -07001037
Andy Hung1ea842e2020-05-18 10:47:31 -07001038 const auto callerNameForStats =
1039 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1040 const auto contentTypeForStats =
1041 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1042 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1043 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1044 const auto streamTypeForStats =
1045 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001046 const auto traitsForStats =
1047 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -07001048 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001049 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001050 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001051
Andy Hunga629bd12020-06-05 16:03:53 -07001052 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001053 << " id:" << id
Andy Hung76adef72022-09-14 17:24:19 -07001054 << " outputDevices:" << outputDevices << "(" << outputDeviceStatsd
Andy Hunga629bd12020-06-05 16:03:53 -07001055 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001056 << " deviceTimeNs:" << deviceTimeNs
1057 << " encoding:" << encoding << "(" << encodingForStats
1058 << ") frameCount:" << frameCount
1059 << " intervalCount:" << intervalCount
1060 << " sampleRate:" << sampleRate
1061 << " underrun:" << underrun
1062 << " flags:" << flags << "(" << flagsForStats
1063 << ") callerName:" << callerName << "(" << callerNameForStats
1064 << ") contentType:" << contentType << "(" << contentTypeForStats
1065 << ") deviceLatencyMs:" << deviceLatencyMs
1066 << " deviceStartupMs:" << deviceStartupMs
1067 << " deviceVolume:" << deviceVolume
1068 << " packageName:" << packageName
1069 << " playbackPitch:" << playbackPitch
1070 << " playbackSpeed:" << playbackSpeed
1071 << " selectedDeviceId:" << selectedDeviceId
1072 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001073 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001074 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001075 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001076 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001077 if (clientCalled // only log if client app called AudioTracks
1078 && mAudioAnalytics.mDeliverStatistics) {
1079 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001080 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung76adef72022-09-14 17:24:19 -07001081 , ENUM_EXTRACT(outputDeviceStatsd)
Andy Hunga629bd12020-06-05 16:03:53 -07001082 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001083 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001084 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001085 , frameCount
1086 , intervalCount
1087 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001088 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001089 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001090 , packageName.c_str()
1091 , (float)deviceLatencyMs
1092 , (float)deviceStartupMs
1093 , (float)deviceVolume
1094 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001095 , ENUM_EXTRACT(streamTypeForStats)
1096 , ENUM_EXTRACT(usageForStats)
1097 , ENUM_EXTRACT(contentTypeForStats)
1098 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001099 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001100 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001101 );
Andy Hunga629bd12020-06-05 16:03:53 -07001102 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001103 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001104 stats::media_metrics::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001105 }
Andy Hungea840382020-05-05 21:50:17 -07001106 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001107 }
Andy Hungce9b6632020-04-28 20:15:17 -07001108}
1109
1110// DeviceConnection helper class.
1111void AudioAnalytics::DeviceConnection::a2dpConnected(
1112 const std::shared_ptr<const android::mediametrics::Item> &item) {
1113 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001114 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001115 {
1116 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001117 mA2dpConnectionServiceNs = atNs;
1118 ++mA2dpConnectionServices;
1119
1120 if (mA2dpConnectionRequestNs == 0) {
1121 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1122 }
1123 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001124 }
1125 std::string name;
1126 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001127 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1128 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001129}
1130
1131void AudioAnalytics::DeviceConnection::createPatch(
1132 const std::shared_ptr<const android::mediametrics::Item> &item) {
1133 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001134 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001135 const std::string& key = item->getKey();
1136 std::string outputDevices;
1137 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001138 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001139 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001140 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001141 if (mA2dpConnectionRequestNs == 0) {
1142 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001143 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001144 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001145 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001146 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001147
Andy Hungea840382020-05-05 21:50:17 -07001148 mA2dpConnectionRequestNs = 0;
1149 mA2dpConnectionServiceNs = 0;
1150 ++mA2dpConnectionSuccesses;
1151
Andy Hungc14ee142021-03-10 16:39:02 -08001152 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001153
1154 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1155 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1156
Andy Hunga629bd12020-06-05 16:03:53 -07001157 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001158 << " A2DP SUCCESS"
1159 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001160 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001161 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001162 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001163 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001164
1165 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001166 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001167 , ENUM_EXTRACT(inputDeviceBits)
1168 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001169 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001170 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1171 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001172 , /* connection_count */ 1
1173 );
Andy Hunga629bd12020-06-05 16:03:53 -07001174 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001175 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001176 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001177 }
Andy Hungce9b6632020-04-28 20:15:17 -07001178 }
1179}
1180
Andy Hungea840382020-05-05 21:50:17 -07001181// Called through AudioManager when the BT service wants to enable
1182void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1183 const std::shared_ptr<const android::mediametrics::Item> &item) {
1184 const int64_t atNs = item->getTimestamp();
1185 const std::string& key = item->getKey();
1186 std::string state;
1187 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1188 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001189
1190 std::string name;
1191 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001192 {
1193 std::lock_guard l(mLock);
1194 mA2dpConnectionRequestNs = atNs;
1195 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001196 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001197 }
Andy Hunga629bd12020-06-05 16:03:53 -07001198 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1199 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001200 // TODO: attempt to cancel a timed event, rather than let it expire.
1201 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1202}
1203
Andy Hungce9b6632020-04-28 20:15:17 -07001204void AudioAnalytics::DeviceConnection::expire() {
1205 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001206 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001207
Andy Hung1ea842e2020-05-18 10:47:31 -07001208 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001209 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1210 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1211
Andy Hungea840382020-05-05 21:50:17 -07001212 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001213 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001214
Andy Hunga629bd12020-06-05 16:03:53 -07001215 LOG(LOG_LEVEL) << "A2DP CANCEL"
1216 << " outputDevices:" << outputDeviceBits
1217 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001218 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001219 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001220 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001221 , ENUM_EXTRACT(inputDeviceBits)
1222 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001223 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001224 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001225 , /* connection_time_ms */ 0.f
1226 , /* connection_count */ 1
1227 );
Andy Hunga629bd12020-06-05 16:03:53 -07001228 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001229 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001230 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001231 }
Andy Hungea840382020-05-05 21:50:17 -07001232 return;
1233 }
1234
1235 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1236 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001237 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001238 mA2dpConnectionRequestNs = 0;
1239 mA2dpConnectionServiceNs = 0;
1240 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001241
Andy Hunga629bd12020-06-05 16:03:53 -07001242 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1243 << " outputDevices:" << outputDeviceBits
1244 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001245 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001246 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001247 CONDITION(stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001248 , ENUM_EXTRACT(inputDeviceBits)
1249 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001250 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001251 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001252 , /* connection_time_ms */ 0.f
1253 , /* connection_count */ 1
1254 );
Andy Hunga629bd12020-06-05 16:03:53 -07001255 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001256 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001257 stats::media_metrics::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001258 }
Andy Hungce9b6632020-04-28 20:15:17 -07001259}
1260
jiabin515eb092020-11-18 17:55:52 -08001261void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1262 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1263 const std::string& key = item->getKey();
1264
jiabin515eb092020-11-18 17:55:52 -08001265 std::string directionStr;
1266 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1267 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1268 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1269
1270 int32_t framesPerBurst = -1;
1271 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1272 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1273
1274 int32_t bufferSizeInFrames = -1;
1275 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1276 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1277
1278 int32_t bufferCapacityInFrames = -1;
1279 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1280 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1281
1282 int32_t channelCount = -1;
1283 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1284 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001285 if (channelCount == -1) {
1286 // Try to get channel count from channel mask. From the legacy path,
1287 // only channel mask are logged.
1288 int32_t channelMask = 0;
1289 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1290 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1291 if (channelMask != 0) {
1292 switch (direction) {
1293 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001294 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001295 break;
1296 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001297 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001298 break;
1299 default:
1300 ALOGW("Invalid direction %d", direction);
1301 }
1302 }
1303 }
jiabin515eb092020-11-18 17:55:52 -08001304
1305 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001306 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1307 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001308
1309 std::string perfModeRequestedStr;
1310 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1311 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1312 const auto perfModeRequested =
1313 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1314
jiabin97247ea2021-04-07 00:33:38 +00001315 std::string perfModeActualStr;
1316 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1317 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1318 const auto perfModeActual =
1319 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001320
jiabinc8da9032021-04-28 20:42:36 +00001321 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001322 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001323 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1324 const auto sharingModeActual =
1325 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001326
1327 int32_t xrunCount = -1;
1328 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1329 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1330
jiabin92c9a522021-02-12 22:37:42 +00001331 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001332 // TODO: only routed device id is logged, but no device type
1333
jiabin97247ea2021-04-07 00:33:38 +00001334 std::string formatAppStr;
1335 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001336 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001337 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001338
1339 std::string formatDeviceStr;
1340 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1341 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1342 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1343
jiabin92c9a522021-02-12 22:37:42 +00001344 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001345 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1346 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001347
jiabinc4c331c2021-03-23 17:11:01 +00001348 int32_t sampleRate = 0;
1349 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1350 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1351
1352 std::string contentTypeStr;
1353 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1354 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1355 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1356
jiabinc8da9032021-04-28 20:42:36 +00001357 std::string sharingModeRequestedStr;
1358 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1359 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1360 const auto sharingModeRequested =
1361 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1362
jiabin515eb092020-11-18 17:55:52 -08001363 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001364 << " path:" << path
1365 << " direction:" << direction << "(" << directionStr << ")"
1366 << " frames_per_burst:" << framesPerBurst
1367 << " buffer_size:" << bufferSizeInFrames
1368 << " buffer_capacity:" << bufferCapacityInFrames
1369 << " channel_count:" << channelCount
1370 << " total_frames_transferred:" << totalFramesTransferred
1371 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001372 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001373 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001374 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001375 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001376 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001377 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001378 << " log_session_id: " << logSessionId
1379 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001380 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1381 << " sharing_requested:" << sharingModeRequested
1382 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001383
jiabin92c9a522021-02-12 22:37:42 +00001384 if (mAudioAnalytics.mDeliverStatistics) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001385 const stats::media_metrics::BytesField bf_serialized(
jiabin92c9a522021-02-12 22:37:42 +00001386 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1387 const auto result = sendToStatsd(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001388 CONDITION(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001389 , path
1390 , direction
1391 , framesPerBurst
1392 , bufferSizeInFrames
1393 , bufferCapacityInFrames
1394 , channelCount
1395 , totalFramesTransferred
1396 , perfModeRequested
1397 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001398 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001399 , xrunCount
1400 , bf_serialized
1401 , formatApp
1402 , formatDevice
1403 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001404 , sampleRate
1405 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001406 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001407 );
1408 std::stringstream ss;
1409 ss << "result:" << result;
1410 const auto fieldsStr = printFields(AAudioStreamFields,
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 , serializedDeviceTypes.c_str()
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
jiabin92c9a522021-02-12 22:37:42 +00001430 );
1431 ss << " " << fieldsStr;
1432 std::string str = ss.str();
1433 ALOGV("%s: statsd %s", __func__, str.c_str());
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001434 mAudioAnalytics.mStatsdLog->log(stats::media_metrics::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001435 }
jiabin515eb092020-11-18 17:55:52 -08001436}
1437
Andy Hungf4eaa462022-03-09 21:53:09 -08001438// Create new state, typically occurs after an AudioFlinger ctor event.
1439void AudioAnalytics::newState()
1440{
1441 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1442 *mAnalyticsState.get()));
1443 // Note: get returns shared_ptr temp, whose lifetime is extended
1444 // to end of full expression.
1445 mAnalyticsState->clear(); // TODO: filter the analytics state.
1446 // Perhaps report this.
1447
1448 // Set up a timer to expire the previous audio state to save space.
1449 // Use the transaction log size as a cookie to see if it is the
1450 // same as before. A benign race is possible where a state is cleared early.
1451 const size_t size = mPreviousAnalyticsState->transactionLog().size();
1452 mTimedAction.postIn(
1453 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1454 if (mPreviousAnalyticsState->transactionLog().size() == size) {
1455 ALOGD("expiring previous audio state after %d seconds.",
1456 PREVIOUS_STATE_EXPIRE_SEC);
1457 mPreviousAnalyticsState->clear(); // removes data from the state.
1458 }
1459 });
1460}
1461
1462void AudioAnalytics::Health::onAudioServerStart(Module module,
1463 const std::shared_ptr<const android::mediametrics::Item> &item)
1464{
1465 const auto nowTime = std::chrono::system_clock::now();
1466 if (module == Module::AUDIOFLINGER) {
1467 {
1468 std::lock_guard lg(mLock);
1469 // reset state on AudioFlinger construction.
1470 // AudioPolicy is created after AudioFlinger.
1471 mAudioFlingerCtorTime = nowTime;
1472 mSimpleLog.log("AudioFlinger ctor");
1473 }
1474 mAudioAnalytics.newState();
1475 return;
1476 }
1477 if (module == Module::AUDIOPOLICY) {
1478 // A start event occurs when audioserver
1479 //
1480 // (1) Starts the first time
1481 // (2) Restarts because of the TimeCheck watchdog
1482 // (3) Restarts not because of the TimeCheck watchdog.
1483 int64_t executionTimeNs = 0;
1484 (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1485 const float loadTimeMs = executionTimeNs * 1e-6f;
1486 std::lock_guard lg(mLock);
1487 const int64_t restarts = mStartCount;
1488 if (mStopCount == mStartCount) {
1489 mAudioPolicyCtorTime = nowTime;
1490 ++mStartCount;
1491 if (mStopCount == 0) {
1492 // (1) First time initialization.
1493 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1494 __func__, item->getKey().c_str(), loadTimeMs);
1495 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1496 } else {
1497 // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
1498 const float restartMs =
1499 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1500 mAudioFlingerCtorTime - mStopTime).count();
1501 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1502 "restarts:%lld restartMs:%f loadTimeMs:%f",
1503 __func__, item->getKey().c_str(),
1504 (long long)restarts, restartMs, loadTimeMs);
1505 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1506 (long long)restarts, restartMs, loadTimeMs);
1507 }
1508 } else {
1509 // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1510 // However we can estimate the uptime from the delta time from previous ctor.
1511 const float uptimeMs =
1512 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1513 nowTime - mAudioFlingerCtorTime).count();
1514 mStopCount = mStartCount;
1515 mAudioPolicyCtorTime = nowTime;
1516 ++mStartCount;
1517
1518 ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1519 "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1520 __func__, item->getKey().c_str(),
1521 (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1522 mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1523 "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1524 (long long)restarts, uptimeMs, loadTimeMs);
1525 }
1526 }
1527}
1528
1529void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1530 const std::shared_ptr<const android::mediametrics::Item> &item)
1531{
1532 std::string moduleName = getModuleName(module);
1533 int64_t methodCode{};
1534 std::string methodName;
1535 (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1536 (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1537
1538 std::lock_guard lg(mLock);
1539 if (mStopCount >= mStartCount) {
1540 ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1541 "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1542 __func__, item->getKey().c_str(), moduleName.c_str(),
1543 methodName.c_str(), (long long)methodCode,
1544 (long long)mStopCount, (long long)mStartCount);
1545 return;
1546 }
1547
1548 const int64_t restarts = mStartCount - 1;
1549 ++mStopCount;
1550 mStopTime = std::chrono::system_clock::now();
1551 const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1552 mStopTime - mAudioFlingerCtorTime).count();
1553 ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1554 __func__, item->getKey().c_str(), moduleName.c_str(),
1555 methodName.c_str(), (long long)methodCode,
1556 (long long)restarts, uptimeMs);
1557 mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1558 moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1559 (long long)restarts, uptimeMs);
1560}
1561
1562std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1563 int32_t lines, const char *prefix) const
1564{
1565 std::lock_guard lg(mLock);
1566 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1567 size_t n = std::count(s.begin(), s.end(), '\n');
1568 return { s, n };
1569}
1570
Andy Hung05874e82022-08-17 17:27:32 -07001571// Classifies the setting event for statsd (use generated statsd enums.proto constants).
1572static int32_t classifySettingEvent(bool isSetAlready, bool withinBoot) {
1573 if (isSetAlready) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001574 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_NORMAL;
Andy Hung05874e82022-08-17 17:27:32 -07001575 }
1576 if (withinBoot) {
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001577 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_BOOT;
Andy Hung05874e82022-08-17 17:27:32 -07001578 }
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001579 return stats::media_metrics::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_FIRST;
Andy Hung05874e82022-08-17 17:27:32 -07001580}
1581
Andy Hunge0d43b42022-08-18 19:20:48 -07001582void AudioAnalytics::Spatializer::onEvent(
1583 const std::shared_ptr<const android::mediametrics::Item> &item)
1584{
1585 const auto key = item->getKey();
1586
1587 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1588
1589 const std::string suffix =
1590 key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1591
1592 std::string eventStr; // optional - find the actual event string.
1593 (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1594
1595 const size_t delim = suffix.find('.'); // note could use split.
1596 if (delim == suffix.npos) {
1597 // on create with suffix == "0" for the first spatializer effect.
1598
1599 std::string headTrackingModes;
1600 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1601
1602 std::string levels;
1603 (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1604
1605 std::string modes;
1606 (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1607
Andy Hung05874e82022-08-17 17:27:32 -07001608 std::string channelMasks;
1609 (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASKS, &channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001610
1611 LOG(LOG_LEVEL) << "key:" << key
1612 << " headTrackingModes:" << headTrackingModes
1613 << " levels:" << levels
1614 << " modes:" << modes
Andy Hung05874e82022-08-17 17:27:32 -07001615 << " channelMasks:" << channelMasks
Andy Hunge0d43b42022-08-18 19:20:48 -07001616 ;
1617
1618 const std::vector<int32_t> headTrackingModesVector =
1619 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1620 const std::vector<int32_t> levelsVector =
1621 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1622 const std::vector<int32_t> modesVector =
1623 types::vectorFromMap(modes, types::getSpatializerModeMap());
Andy Hung05874e82022-08-17 17:27:32 -07001624 const std::vector<int64_t> channelMasksVector =
1625 types::channelMaskVectorFromString(channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001626
Andy Hung05874e82022-08-17 17:27:32 -07001627 const auto [ result, str ] = sendToStatsd(SpatializerCapabilitiesFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001628 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001629 , headTrackingModesVector
1630 , levelsVector
1631 , modesVector
1632 , channelMasksVector
1633 );
1634
1635 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001636 stats::media_metrics::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001637
1638 std::lock_guard lg(mLock);
Andy Hung05874e82022-08-17 17:27:32 -07001639 if (mFirstCreateTimeNs == 0) {
1640 // Only update the create time once to prevent audioserver restart
1641 // from looking like a boot.
1642 mFirstCreateTimeNs = item->getTimestamp();
1643 }
Andy Hunge0d43b42022-08-18 19:20:48 -07001644 mSimpleLog.log("%s suffix: %s item: %s",
1645 __func__, suffix.c_str(), item->toString().c_str());
1646 } else {
1647 std::string subtype = suffix.substr(0, delim);
1648 if (subtype != "device") return; // not a device.
1649
Andy Hung05874e82022-08-17 17:27:32 -07001650 const std::string deviceType = suffix.substr(std::size("device.") - 1);
Andy Hunge0d43b42022-08-18 19:20:48 -07001651
Andy Hung05874e82022-08-17 17:27:32 -07001652 const int32_t deviceTypeStatsd =
1653 types::lookup<types::AUDIO_DEVICE_INFO_TYPE, int32_t>(deviceType);
1654
1655 std::string address;
1656 (void)item->get(AMEDIAMETRICS_PROP_ADDRESS, &address);
Andy Hunge0d43b42022-08-18 19:20:48 -07001657 std::string enabled;
1658 (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1659 std::string hasHeadTracker;
1660 (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1661 std::string headTrackerEnabled;
1662 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1663
1664 std::lock_guard lg(mLock);
1665
1666 // Validate from our cached state
Andy Hung05874e82022-08-17 17:27:32 -07001667
1668 // Our deviceKey takes the device type and appends the address if any.
1669 // This distinguishes different wireless devices for the purposes of tracking.
1670 std::string deviceKey(deviceType);
1671 deviceKey.append("_").append(address);
1672 DeviceState& deviceState = mDeviceStateMap[deviceKey];
1673
1674 // check whether the settings event is within a certain time of spatializer creation.
1675 const bool withinBoot =
1676 item->getTimestamp() - mFirstCreateTimeNs < kBootDurationThreshold;
Andy Hunge0d43b42022-08-18 19:20:48 -07001677
1678 if (!enabled.empty()) {
1679 if (enabled != deviceState.enabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001680 const int32_t settingEventStatsd =
1681 classifySettingEvent(!deviceState.enabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001682 deviceState.enabled = enabled;
1683 const bool enabledStatsd = enabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001684 const auto [ result, str ] = sendToStatsd(SpatializerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001685 CONDITION(stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001686 , deviceTypeStatsd
1687 , settingEventStatsd
1688 , enabledStatsd
1689 );
1690 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001691 stats::media_metrics::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001692 }
1693 }
1694 if (!hasHeadTracker.empty()) {
1695 if (hasHeadTracker != deviceState.hasHeadTracker) {
Andy Hung05874e82022-08-17 17:27:32 -07001696 const int32_t settingEventStatsd =
1697 classifySettingEvent(!deviceState.hasHeadTracker.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001698 deviceState.hasHeadTracker = hasHeadTracker;
1699 const bool supportedStatsd = hasHeadTracker == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001700 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceSupportedFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001701 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001702 , deviceTypeStatsd
1703 , settingEventStatsd
1704 , supportedStatsd
1705 );
1706 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001707 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001708 }
1709 }
1710 if (!headTrackerEnabled.empty()) {
1711 if (headTrackerEnabled != deviceState.headTrackerEnabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001712 const int32_t settingEventStatsd =
1713 classifySettingEvent(!deviceState.headTrackerEnabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001714 deviceState.headTrackerEnabled = headTrackerEnabled;
1715 const bool enabledStatsd = headTrackerEnabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001716 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceEnabledFields,
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001717 CONDITION(stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED)
Andy Hung05874e82022-08-17 17:27:32 -07001718 , deviceTypeStatsd
1719 , settingEventStatsd
1720 , enabledStatsd
1721 );
1722 mAudioAnalytics.mStatsdLog->log(
Vova Sharaienkof58455a2022-09-24 01:47:23 +00001723 stats::media_metrics::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001724 }
1725 }
Andy Hung05874e82022-08-17 17:27:32 -07001726 mSimpleLog.log("%s deviceKey: %s item: %s",
1727 __func__, deviceKey.c_str(), item->toString().c_str());
Andy Hunge0d43b42022-08-18 19:20:48 -07001728 }
1729}
1730
1731std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1732 int32_t lines, const char *prefix) const
1733{
1734 std::lock_guard lg(mLock);
1735 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1736 size_t n = std::count(s.begin(), s.end(), '\n');
1737 return { s, n };
1738}
Andy Hungf4eaa462022-03-09 21:53:09 -08001739
Robert Wu38439732022-11-02 23:16:04 +00001740void AudioAnalytics::MidiLogging::onEvent(
1741 const std::shared_ptr<const android::mediametrics::Item> &item) const {
1742 const std::string& key = item->getKey();
1743
1744 const auto uid = item->getUid();
1745
1746 int32_t deviceId = -1;
1747 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1748 key, AMEDIAMETRICS_PROP_DEVICEID, &deviceId);
1749
1750 int32_t inputPortCount = -1;
1751 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1752 key, AMEDIAMETRICS_PROP_INPUTPORTCOUNT, &inputPortCount);
1753
1754 int32_t outputPortCount = -1;
1755 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1756 key, AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT, &outputPortCount);
1757
1758 int32_t hardwareType = -1;
1759 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1760 key, AMEDIAMETRICS_PROP_HARDWARETYPE, &hardwareType);
1761
1762 std::string isSharedString;
1763 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1764 key, AMEDIAMETRICS_PROP_ISSHARED, &isSharedString);
1765 const bool isShared = (isSharedString == "true");
1766
1767 std::string supportsMidiUmpString;
1768 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1769 key, AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP, &supportsMidiUmpString);
1770 const bool supportsMidiUmp = (supportsMidiUmpString == "true");
1771
1772 std::string usingAlsaString;
1773 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1774 key, AMEDIAMETRICS_PROP_USINGALSA, &usingAlsaString);
1775 const bool usingAlsa = (usingAlsaString == "true");
1776
1777 int64_t durationNs = -1;
1778 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1779 key, AMEDIAMETRICS_PROP_DURATIONNS, &durationNs);
1780
1781 int32_t openedCount = -1;
1782 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1783 key, AMEDIAMETRICS_PROP_OPENEDCOUNT, &openedCount);
1784
1785 int32_t closedCount = -1;
1786 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1787 key, AMEDIAMETRICS_PROP_CLOSEDCOUNT, &closedCount);
1788
1789 std::string deviceDisconnectedString;
1790 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1791 key, AMEDIAMETRICS_PROP_DEVICEDISCONNECTED, &deviceDisconnectedString);
1792 const bool deviceDisconnected = (deviceDisconnectedString == "true");
1793
1794 int32_t totalInputBytes = -1;
1795 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1796 key, AMEDIAMETRICS_PROP_TOTALINPUTBYTES, &totalInputBytes);
1797
1798 int32_t totalOutputBytes = -1;
1799 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1800 key, AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES, &totalOutputBytes);
1801
1802 LOG(LOG_LEVEL) << "key:" << key
1803 << " uid:" << uid
1804 << " id:" << deviceId
1805 << " input_port_count:" << inputPortCount
1806 << " output_port_count:" << outputPortCount
1807 << " device_type:" << hardwareType
1808 << " is_shared:" << isSharedString
1809 << " supports_ump:" << supportsMidiUmpString
1810 << " using_alsa:" << usingAlsaString
1811 << " duration_opened_ms:" << durationNs
1812 << " opened_count:" << openedCount
1813 << " closed_count:" << closedCount
1814 << " device_disconnected:" << deviceDisconnectedString
1815 << " total_input_bytes:" << totalInputBytes
1816 << " total_output_bytes:" << totalOutputBytes;
1817
1818 if (mAudioAnalytics.mDeliverStatistics) {
1819 const auto result = sendToStatsd(
1820 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1821 , uid
1822 , deviceId
1823 , inputPortCount
1824 , outputPortCount
1825 , hardwareType
1826 , isShared
1827 , supportsMidiUmp
1828 , usingAlsa
1829 , durationNs
1830 , openedCount
1831 , closedCount
1832 , deviceDisconnected
1833 , totalInputBytes
1834 , totalOutputBytes);
1835 std::stringstream ss;
1836 ss << "result:" << result;
1837 const auto fieldsStr = printFields(MidiDeviceCloseFields,
1838 CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
1839 , uid
1840 , deviceId
1841 , inputPortCount
1842 , outputPortCount
1843 , hardwareType
1844 , isShared
1845 , supportsMidiUmp
1846 , usingAlsa
1847 , durationNs
1848 , openedCount
1849 , closedCount
1850 , deviceDisconnected
1851 , totalInputBytes
1852 , totalOutputBytes);
1853 ss << " " << fieldsStr;
1854 std::string str = ss.str();
1855 ALOGV("%s: statsd %s", __func__, str.c_str());
1856 mAudioAnalytics.mStatsdLog->log(
1857 stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED, str);
1858 }
1859}
1860
Andy Hung76adef72022-09-14 17:24:19 -07001861// This method currently suppresses the name.
1862std::string AudioAnalytics::getDeviceNamesFromOutputDevices(std::string_view devices) const {
1863 std::string deviceNames;
1864 if (stringutils::hasBluetoothOutputDevice(devices)) {
1865 deviceNames = SUPPRESSED;
1866#if 0 // TODO(b/161554630) sanitize name
1867 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1868 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
1869 // Remove | if present
1870 stringutils::replace(deviceNames, "|", '?');
1871 if (deviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
1872 deviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
1873 }
1874#endif
1875 }
1876 return deviceNames;
1877}
1878
Andy Hung3ab1b322020-05-18 10:47:31 -07001879} // namespace android::mediametrics