blob: 12593ffd6a9df8632aee5d030f10d81f9c3b988f [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>
Andy Hungce9b6632020-04-28 20:15:17 -070027#include <statslog.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
jiabin92c9a522021-02-12 22:37:42 +0000272/**
273 * printFields is a helper method that prints the fields and corresponding values
274 * in a human readable style.
275 */
276template <size_t N, typename ...Types>
277std::string printFields(const char * const (& fields)[N], Types ... args)
278{
279 std::stringstream ss;
280 ss << " { ";
281 stringutils::fieldPrint(ss, fields, args...);
282 ss << "}";
283 return ss.str();
284}
285
286/**
287 * sendToStatsd is a helper method that sends the arguments to statsd
288 */
289template <typename ...Types>
290int sendToStatsd(Types ... args)
291{
292 int result = 0;
293
294#ifdef STATSD_ENABLE
295 result = android::util::stats_write(args...);
296#endif
297 return result;
298}
jiabin515eb092020-11-18 17:55:52 -0800299
Andy Hunga629bd12020-06-05 16:03:53 -0700300/**
301 * sendToStatsd is a helper method that sends the arguments to statsd
302 * and returns a pair { result, summary_string }.
303 */
304template <size_t N, typename ...Types>
305std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
306{
307 int result = 0;
308 std::stringstream ss;
309
310#ifdef STATSD_ENABLE
311 result = android::util::stats_write(args...);
312 ss << "result:" << result;
313#endif
314 ss << " { ";
315 stringutils::fieldPrint(ss, fields, args...);
316 ss << "}";
317 return { result, ss.str() };
318}
Andy Hung06f3aba2019-12-03 16:36:42 -0800319
Andy Hung5be90c82021-03-30 14:30:20 -0700320AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700321 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700322 , mStatsdLog(statsdLog)
323 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800324{
Andy Hunga629bd12020-06-05 16:03:53 -0700325 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800326 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800327
328 // Add action to save AnalyticsState if audioserver is restarted.
Andy Hungf4eaa462022-03-09 21:53:09 -0800329 // This triggers on AudioFlinger or AudioPolicy ctors and onFirstRef,
330 // as well as TimeCheck events.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800331 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800332 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
333 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800334 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800335 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungf4eaa462022-03-09 21:53:09 -0800336 mHealth.onAudioServerStart(Health::Module::AUDIOFLINGER, item);
337 }));
338 mActions.addAction(
339 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
340 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
341 std::make_shared<AnalyticsActions::Function>(
342 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
343 mHealth.onAudioServerStart(Health::Module::AUDIOPOLICY, item);
344 }));
345 mActions.addAction(
346 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
347 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
348 std::make_shared<AnalyticsActions::Function>(
349 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
350 mHealth.onAudioServerTimeout(Health::Module::AUDIOFLINGER, item);
351 }));
352 mActions.addAction(
353 AMEDIAMETRICS_KEY_AUDIO_POLICY "." AMEDIAMETRICS_PROP_EVENT,
354 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_TIMEOUT),
355 std::make_shared<AnalyticsActions::Function>(
356 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
357 mHealth.onAudioServerTimeout(Health::Module::AUDIOPOLICY, item);
Andy Hungea186fa2020-01-09 18:13:15 -0800358 }));
359
jiabin97247ea2021-04-07 00:33:38 +0000360 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800361 mActions.addAction(
362 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
363 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
364 std::make_shared<AnalyticsActions::Function>(
365 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
366 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
367 }));
368
jiabin97247ea2021-04-07 00:33:38 +0000369 // Handle legacy aaudio capture stream statistics
370 mActions.addAction(
371 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
372 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
373 std::make_shared<AnalyticsActions::Function>(
374 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
375 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
376 }));
377
jiabin515eb092020-11-18 17:55:52 -0800378 // Handle mmap aaudio stream statistics
379 mActions.addAction(
380 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." 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_MMAP);
385 }));
386
Andy Hungea840382020-05-05 21:50:17 -0700387 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800388 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700389 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
390 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800391 std::make_shared<AnalyticsActions::Function>(
392 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700393 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800394 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700395
396 // Handle device use thread statistics
397 mActions.addAction(
398 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
399 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
400 std::make_shared<AnalyticsActions::Function>(
401 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700402 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700403 }));
404
405 // Handle device use track statistics
406 mActions.addAction(
407 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
408 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
409 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::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700412 }));
413
Andy Hungea840382020-05-05 21:50:17 -0700414
415 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700416
417 // We track connections (not disconnections) for the time to connect.
418 // TODO: consider BT requests in their A2dp service
419 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
420 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
421 // AudioDeviceBroker.postA2dpActiveDeviceChange
422 mActions.addAction(
423 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700424 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700425 std::make_shared<AnalyticsActions::Function>(
426 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
427 mDeviceConnection.a2dpConnected(item);
428 }));
429 // If audio is active, we expect to see a createAudioPatch after the device is connected.
430 mActions.addAction(
431 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
432 std::string("createAudioPatch"),
433 std::make_shared<AnalyticsActions::Function>(
434 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
435 mDeviceConnection.createPatch(item);
436 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800437
Andy Hungea840382020-05-05 21:50:17 -0700438 // Called from BT service
439 mActions.addAction(
440 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
441 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
442 "." AMEDIAMETRICS_PROP_STATE,
443 "connected",
444 std::make_shared<AnalyticsActions::Function>(
445 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
446 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
447 }));
448
Joey Poomarin52989982020-03-05 17:40:49 +0800449 // Handle power usage
450 mActions.addAction(
451 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
452 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
453 std::make_shared<AnalyticsActions::Function>(
454 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
455 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
456 }));
457
458 mActions.addAction(
459 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
460 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
461 std::make_shared<AnalyticsActions::Function>(
462 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
463 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
464 }));
465
466 mActions.addAction(
467 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
468 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
469 std::make_shared<AnalyticsActions::Function>(
470 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
471 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
472 mAudioPowerUsage.checkMode(item);
473 }));
474
475 mActions.addAction(
476 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
477 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
478 std::make_shared<AnalyticsActions::Function>(
479 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
480 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
481 mAudioPowerUsage.checkVoiceVolume(item);
482 }));
483
484 mActions.addAction(
485 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
486 std::string("createAudioPatch"),
487 std::make_shared<AnalyticsActions::Function>(
488 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
489 mAudioPowerUsage.checkCreatePatch(item);
490 }));
Andy Hunge0d43b42022-08-18 19:20:48 -0700491
492 // Handle Spatializer - these keys are prefixed by "audio.spatializer."
493 mActions.addAction(
494 AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "*." AMEDIAMETRICS_PROP_EVENT,
495 std::monostate{}, /* match any event */
496 std::make_shared<AnalyticsActions::Function>(
497 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
498 mSpatializer.onEvent(item);
499 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800500}
501
502AudioAnalytics::~AudioAnalytics()
503{
504 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700505 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800506}
507
508status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800509 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800510{
Andy Hungea186fa2020-01-09 18:13:15 -0800511 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800512 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800513
514 // Status is selectively authenticated.
515 processStatus(item);
516
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800517 if (status != NO_ERROR) return status; // may not be permitted.
518
519 // Only if the item was successfully submitted (permission)
520 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800521 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800522 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800523}
524
Andy Hung709b91e2020-04-04 14:23:36 -0700525std::pair<std::string, int32_t> AudioAnalytics::dump(
526 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800527{
528 std::stringstream ss;
529 int32_t ll = lines;
530
531 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700532 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700533 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800534 ll -= l;
535 }
536 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800537 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800538 --ll;
539 }
540 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700541 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700542 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800543 ll -= l;
544 }
Joey Poomarin52989982020-03-05 17:40:49 +0800545
546 if (ll > 0 && prefix == nullptr) {
547 auto [s, l] = mAudioPowerUsage.dump(ll);
548 ss << s;
549 ll -= l;
550 }
Andy Hunga629bd12020-06-05 16:03:53 -0700551
Andy Hung06f3aba2019-12-03 16:36:42 -0800552 return { ss.str(), lines - ll };
553}
554
Andy Hung73dc2f92021-12-07 21:50:04 -0800555void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800556{
557 auto actions = mActions.getActionsForItem(item); // internally locked.
558 // Execute actions with no lock held.
559 for (const auto& action : actions) {
560 (*action)(item);
561 }
562}
563
Andy Hung73dc2f92021-12-07 21:50:04 -0800564void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
565{
566 int32_t status;
567 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
568
569 // Any record with a status will automatically be added to a heat map.
570 // Standard information.
571 const auto key = item->getKey();
572 const auto uid = item->getUid();
573
574 // from audio.track.10 -> prefix = audio.track, suffix = 10
575 // from audio.track.error -> prefix = audio.track, suffix = error
576 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
577
578 std::string message;
579 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
580
581 int32_t subCode = 0; // not used
582 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
583
584 std::string eventStr; // optional
585 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
586
587 const std::string statusString = extendedStatusToStatusString(status);
588
589 // Add to the heat map - we automatically track every item's status to see
590 // the types of errors and the frequency of errors.
591 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800592
Andy Hung44326582022-01-11 17:27:09 -0800593 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
594 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
595 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
596}
597
598bool AudioAnalytics::reportAudioRecordStatus(
599 const std::shared_ptr<const mediametrics::Item>& item,
600 const std::string& key, const std::string& eventStr,
601 const std::string& statusString, uid_t uid, const std::string& message,
602 int32_t subCode) const
603{
Andy Hungb8918b52021-12-14 22:15:40 -0800604 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800605 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
606 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
607 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
608
609 // currently we only send create status events.
610 const int32_t event = android::util::
611 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
612
613 // The following fields should all be present in a create event.
614 std::string flagsStr;
615 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
616 "%s: %s missing %s field", __func__,
617 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
618 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
619
620 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
621
622 std::string sourceStr;
623 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
624 "%s: %s missing %s field",
625 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
626 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
627
628 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
629
630 std::string encodingStr;
631 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
632 "%s: %s missing %s field",
633 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
634 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
635
636 int32_t channelMask = 0;
637 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
638 "%s: %s missing %s field",
639 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
640 int32_t frameCount = 0;
641 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
642 "%s: %s missing %s field",
643 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
644 int32_t sampleRate = 0;
645 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
646 "%s: %s missing %s field",
647 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
648
649 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
650 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
651 , atom_status
652 , message.c_str()
653 , subCode
654 , uid
655 , event
656 , flags
657 , source
658 , encoding
659 , (int64_t)channelMask
660 , frameCount
661 , sampleRate
662 );
663 ALOGV("%s: statsd %s", __func__, str.c_str());
664 mStatsdLog->log(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
665 return true;
666 }
667 return false;
668}
669
670bool AudioAnalytics::reportAudioTrackStatus(
671 const std::shared_ptr<const mediametrics::Item>& item,
672 const std::string& key, const std::string& eventStr,
673 const std::string& statusString, uid_t uid, const std::string& message,
674 int32_t subCode) const
675{
676 // Note that the prefixes often end with a '.' so we use startsWith.
677 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
678 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800679 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
680
681 // currently we only send create status events.
Andy Hungcb40b982022-01-31 20:08:25 -0800682 const int32_t event = android::util::
683 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800684
685 // The following fields should all be present in a create event.
686 std::string flagsStr;
687 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
688 "%s: %s missing %s field",
689 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
690 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
691
692 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
693
694 std::string contentTypeStr;
695 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
696 "%s: %s missing %s field",
697 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
698 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
699
700 std::string usageStr;
701 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
702 "%s: %s missing %s field",
703 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
704 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
705
706 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
707
708 std::string encodingStr;
709 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
710 "%s: %s missing %s field",
711 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
712 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
713
714 int32_t channelMask = 0;
715 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
716 "%s: %s missing %s field",
717 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
718 int32_t frameCount = 0;
719 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
720 "%s: %s missing %s field",
721 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
722 int32_t sampleRate = 0;
723 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
724 "%s: %s missing %s field",
725 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
726 double speed = 0.f; // default is 1.f
727 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
728 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800729 __func__,
730 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800731 double pitch = 0.f; // default is 1.f
732 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
733 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800734 __func__,
735 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800736 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
737 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
738 , atom_status
739 , message.c_str()
740 , subCode
741 , uid
742 , event
743 , flags
744 , contentType
745 , usage
746 , encoding
747 , (int64_t)channelMask
748 , frameCount
749 , sampleRate
750 , (float)speed
751 , (float)pitch
752 );
753 ALOGV("%s: statsd %s", __func__, str.c_str());
754 mStatsdLog->log(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800755 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800756 }
Andy Hung44326582022-01-11 17:27:09 -0800757 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800758}
759
Andy Hungea186fa2020-01-09 18:13:15 -0800760// HELPER METHODS
761
762std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
763{
764 int32_t threadId_int32{};
765 if (mAnalyticsState->timeMachine().get(
766 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
767 return {};
768 }
769 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
770}
771
Andy Hungce9b6632020-04-28 20:15:17 -0700772// DeviceUse helper class.
773void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700774 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700775 const std::string& key = item->getKey();
776 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700777 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
778 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
779 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700780 - 1);
781 // deliver statistics
782 int64_t deviceTimeNs = 0;
783 mAudioAnalytics.mAnalyticsState->timeMachine().get(
784 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
785 std::string encoding;
786 mAudioAnalytics.mAnalyticsState->timeMachine().get(
787 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
788 int32_t frameCount = 0;
789 mAudioAnalytics.mAnalyticsState->timeMachine().get(
790 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700791 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700792 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700793 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700794 int32_t intervalCount = 0;
795 mAudioAnalytics.mAnalyticsState->timeMachine().get(
796 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700797 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700798 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700799 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700800 int32_t sampleRate = 0;
801 mAudioAnalytics.mAnalyticsState->timeMachine().get(
802 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700803 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700804 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700805 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700806
Andy Hungea840382020-05-05 21:50:17 -0700807 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700808 // Accumulate the bit flags for input and output devices.
809 std::stringstream oss;
810 long_enum_type_t outputDeviceBits{};
811 { // compute outputDevices
812 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700813 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700814 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
815 oss << device;
816 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700817 }
818 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700819 const std::string outputDevices = oss.str();
820
821 std::stringstream iss;
822 long_enum_type_t inputDeviceBits{};
823 { // compute inputDevices
824 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
825 for (const auto& [device, addr] : devaddrvec) {
826 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
827 iss << device;
828 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
829 }
830 }
831 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700832
833 // Get connected device name if from bluetooth.
834 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700835
836 std::string inputDeviceNames; // not filled currently.
837 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700838 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
839 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700840 outputDeviceNames = SUPPRESSED;
841#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700842 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700843 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700844 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700845 stringutils::replace(outputDeviceNames, "|", '?');
846 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
847 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
848 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700849#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700850 }
851
Andy Hungea840382020-05-05 21:50:17 -0700852 switch (itemType) {
853 case RECORD: {
854 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700855 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
856 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700857
Andy Hungea840382020-05-05 21:50:17 -0700858 std::string packageName;
859 int64_t versionCode = 0;
860 int32_t uid = -1;
861 mAudioAnalytics.mAnalyticsState->timeMachine().get(
862 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
863 if (uid != -1) {
864 std::tie(packageName, versionCode) =
865 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
866 }
867
868 int32_t selectedDeviceId = 0;
869 mAudioAnalytics.mAnalyticsState->timeMachine().get(
870 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
871 std::string source;
872 mAudioAnalytics.mAnalyticsState->timeMachine().get(
873 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800874 // Android S
875 std::string logSessionId;
876 mAudioAnalytics.mAnalyticsState->timeMachine().get(
877 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700878
Andy Hung1ea842e2020-05-18 10:47:31 -0700879 const auto callerNameForStats =
880 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
881 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
882 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
883 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800884 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700885 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700886
Andy Hunga629bd12020-06-05 16:03:53 -0700887 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700888 << " id:" << id
889 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700890 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700891 << " deviceTimeNs:" << deviceTimeNs
892 << " encoding:" << encoding << "(" << encodingForStats
893 << ") frameCount:" << frameCount
894 << " intervalCount:" << intervalCount
895 << " sampleRate:" << sampleRate
896 << " flags:" << flags << "(" << flagsForStats
897 << ") packageName:" << packageName
898 << " selectedDeviceId:" << selectedDeviceId
899 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800900 << ") source:" << source << "(" << sourceForStats
901 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
902 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700903 if (clientCalled // only log if client app called AudioRecord.
904 && mAudioAnalytics.mDeliverStatistics) {
905 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
906 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700907 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700908 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700909 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700910 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700911 , frameCount
912 , intervalCount
913 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700914 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700915
916 , packageName.c_str()
917 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700918 , ENUM_EXTRACT(callerNameForStats)
919 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800920 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700921 );
Andy Hunga629bd12020-06-05 16:03:53 -0700922 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700923 mAudioAnalytics.mStatsdLog->log(
924 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700925 }
Andy Hungea840382020-05-05 21:50:17 -0700926 } break;
927 case THREAD: {
928 std::string type;
929 mAudioAnalytics.mAnalyticsState->timeMachine().get(
930 key, AMEDIAMETRICS_PROP_TYPE, &type);
931 int32_t underrun = 0; // zero for record types
932 mAudioAnalytics.mAnalyticsState->timeMachine().get(
933 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700934
935 const bool isInput = types::isInputThreadType(type);
936 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
937 const auto flagsForStats =
938 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
939 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
940 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
941
Andy Hunga629bd12020-06-05 16:03:53 -0700942 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700943 << " id:" << id
944 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
945 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700946 << ") inputDeviceNames:" << inputDeviceNames
947 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700948 << " deviceTimeNs:" << deviceTimeNs
949 << " encoding:" << encoding << "(" << encodingForStats
950 << ") frameCount:" << frameCount
951 << " intervalCount:" << intervalCount
952 << " sampleRate:" << sampleRate
953 << " underrun:" << underrun
954 << " flags:" << flags << "(" << flagsForStats
955 << ") type:" << type << "(" << typeForStats
956 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700957 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700958 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
959 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
960 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
961 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700962 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700963 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700964 , frameCount
965 , intervalCount
966 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700967 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700968 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700969 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700970 );
Andy Hunga629bd12020-06-05 16:03:53 -0700971 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700972 mAudioAnalytics.mStatsdLog->log(
973 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700974 }
Andy Hungea840382020-05-05 21:50:17 -0700975 } break;
976 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700977 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700978 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
979 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
980
Andy Hungce9b6632020-04-28 20:15:17 -0700981 std::string contentType;
982 mAudioAnalytics.mAnalyticsState->timeMachine().get(
983 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
984 double deviceLatencyMs = 0.;
985 mAudioAnalytics.mAnalyticsState->timeMachine().get(
986 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
987 double deviceStartupMs = 0.;
988 mAudioAnalytics.mAnalyticsState->timeMachine().get(
989 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
990 double deviceVolume = 0.;
991 mAudioAnalytics.mAnalyticsState->timeMachine().get(
992 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
993 std::string packageName;
994 int64_t versionCode = 0;
995 int32_t uid = -1;
996 mAudioAnalytics.mAnalyticsState->timeMachine().get(
997 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
998 if (uid != -1) {
999 std::tie(packageName, versionCode) =
1000 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
1001 }
1002 double playbackPitch = 0.;
1003 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1004 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
1005 double playbackSpeed = 0.;
1006 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1007 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
1008 int32_t selectedDeviceId = 0;
1009 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1010 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -07001011 std::string streamType;
1012 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1013 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001014 std::string traits;
1015 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1016 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -07001017 int32_t underrun = 0;
1018 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1019 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -07001020 std::string usage;
1021 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1022 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001023 // Android S
1024 std::string logSessionId;
1025 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1026 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -07001027
Andy Hung1ea842e2020-05-18 10:47:31 -07001028 const auto callerNameForStats =
1029 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
1030 const auto contentTypeForStats =
1031 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
1032 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
1033 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
1034 const auto streamTypeForStats =
1035 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -07001036 const auto traitsForStats =
1037 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -07001038 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -08001039 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001040 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001041
Andy Hunga629bd12020-06-05 16:03:53 -07001042 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001043 << " id:" << id
1044 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001045 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001046 << " deviceTimeNs:" << deviceTimeNs
1047 << " encoding:" << encoding << "(" << encodingForStats
1048 << ") frameCount:" << frameCount
1049 << " intervalCount:" << intervalCount
1050 << " sampleRate:" << sampleRate
1051 << " underrun:" << underrun
1052 << " flags:" << flags << "(" << flagsForStats
1053 << ") callerName:" << callerName << "(" << callerNameForStats
1054 << ") contentType:" << contentType << "(" << contentTypeForStats
1055 << ") deviceLatencyMs:" << deviceLatencyMs
1056 << " deviceStartupMs:" << deviceStartupMs
1057 << " deviceVolume:" << deviceVolume
1058 << " packageName:" << packageName
1059 << " playbackPitch:" << playbackPitch
1060 << " playbackSpeed:" << playbackSpeed
1061 << " selectedDeviceId:" << selectedDeviceId
1062 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001063 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001064 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001065 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001066 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001067 if (clientCalled // only log if client app called AudioTracks
1068 && mAudioAnalytics.mDeliverStatistics) {
1069 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
1070 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001071 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001072 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001073 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001074 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001075 , frameCount
1076 , intervalCount
1077 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001078 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001079 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001080 , packageName.c_str()
1081 , (float)deviceLatencyMs
1082 , (float)deviceStartupMs
1083 , (float)deviceVolume
1084 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001085 , ENUM_EXTRACT(streamTypeForStats)
1086 , ENUM_EXTRACT(usageForStats)
1087 , ENUM_EXTRACT(contentTypeForStats)
1088 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001089 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001090 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001091 );
Andy Hunga629bd12020-06-05 16:03:53 -07001092 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001093 mAudioAnalytics.mStatsdLog->log(
1094 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001095 }
Andy Hungea840382020-05-05 21:50:17 -07001096 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001097 }
1098
1099 // Report this as needed.
1100 if (isBluetooth) {
1101 // report this for Bluetooth
1102 }
1103}
1104
1105// DeviceConnection helper class.
1106void AudioAnalytics::DeviceConnection::a2dpConnected(
1107 const std::shared_ptr<const android::mediametrics::Item> &item) {
1108 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001109 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001110 {
1111 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001112 mA2dpConnectionServiceNs = atNs;
1113 ++mA2dpConnectionServices;
1114
1115 if (mA2dpConnectionRequestNs == 0) {
1116 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1117 }
1118 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001119 }
1120 std::string name;
1121 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001122 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1123 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001124}
1125
1126void AudioAnalytics::DeviceConnection::createPatch(
1127 const std::shared_ptr<const android::mediametrics::Item> &item) {
1128 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001129 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001130 const std::string& key = item->getKey();
1131 std::string outputDevices;
1132 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001133 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001134 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001135 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001136 if (mA2dpConnectionRequestNs == 0) {
1137 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001138 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001139 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001140 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001141 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001142
Andy Hungea840382020-05-05 21:50:17 -07001143 mA2dpConnectionRequestNs = 0;
1144 mA2dpConnectionServiceNs = 0;
1145 ++mA2dpConnectionSuccesses;
1146
Andy Hungc14ee142021-03-10 16:39:02 -08001147 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001148
1149 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1150 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1151
Andy Hunga629bd12020-06-05 16:03:53 -07001152 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001153 << " A2DP SUCCESS"
1154 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001155 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001156 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001157 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001158 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001159
1160 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1161 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001162 , ENUM_EXTRACT(inputDeviceBits)
1163 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001164 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001165 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1166 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001167 , /* connection_count */ 1
1168 );
Andy Hunga629bd12020-06-05 16:03:53 -07001169 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001170 mAudioAnalytics.mStatsdLog->log(
1171 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001172 }
Andy Hungce9b6632020-04-28 20:15:17 -07001173 }
1174}
1175
Andy Hungea840382020-05-05 21:50:17 -07001176// Called through AudioManager when the BT service wants to enable
1177void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1178 const std::shared_ptr<const android::mediametrics::Item> &item) {
1179 const int64_t atNs = item->getTimestamp();
1180 const std::string& key = item->getKey();
1181 std::string state;
1182 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1183 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001184
1185 std::string name;
1186 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001187 {
1188 std::lock_guard l(mLock);
1189 mA2dpConnectionRequestNs = atNs;
1190 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001191 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001192 }
Andy Hunga629bd12020-06-05 16:03:53 -07001193 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1194 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001195 // TODO: attempt to cancel a timed event, rather than let it expire.
1196 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1197}
1198
Andy Hungce9b6632020-04-28 20:15:17 -07001199void AudioAnalytics::DeviceConnection::expire() {
1200 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001201 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001202
Andy Hung1ea842e2020-05-18 10:47:31 -07001203 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001204 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1205 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1206
Andy Hungea840382020-05-05 21:50:17 -07001207 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001208 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001209
Andy Hunga629bd12020-06-05 16:03:53 -07001210 LOG(LOG_LEVEL) << "A2DP CANCEL"
1211 << " outputDevices:" << outputDeviceBits
1212 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001213 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001214 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1215 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001216 , ENUM_EXTRACT(inputDeviceBits)
1217 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001218 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001219 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001220 , /* connection_time_ms */ 0.f
1221 , /* connection_count */ 1
1222 );
Andy Hunga629bd12020-06-05 16:03:53 -07001223 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001224 mAudioAnalytics.mStatsdLog->log(
1225 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001226 }
Andy Hungea840382020-05-05 21:50:17 -07001227 return;
1228 }
1229
1230 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1231 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001232 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001233 mA2dpConnectionRequestNs = 0;
1234 mA2dpConnectionServiceNs = 0;
1235 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001236
Andy Hunga629bd12020-06-05 16:03:53 -07001237 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1238 << " outputDevices:" << outputDeviceBits
1239 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001240 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001241 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1242 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001243 , ENUM_EXTRACT(inputDeviceBits)
1244 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001245 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001246 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001247 , /* connection_time_ms */ 0.f
1248 , /* connection_count */ 1
1249 );
Andy Hunga629bd12020-06-05 16:03:53 -07001250 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001251 mAudioAnalytics.mStatsdLog->log(
1252 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001253 }
Andy Hungce9b6632020-04-28 20:15:17 -07001254}
1255
jiabin515eb092020-11-18 17:55:52 -08001256void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1257 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1258 const std::string& key = item->getKey();
1259
jiabin515eb092020-11-18 17:55:52 -08001260 std::string directionStr;
1261 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1262 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1263 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1264
1265 int32_t framesPerBurst = -1;
1266 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1267 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1268
1269 int32_t bufferSizeInFrames = -1;
1270 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1271 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1272
1273 int32_t bufferCapacityInFrames = -1;
1274 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1275 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1276
1277 int32_t channelCount = -1;
1278 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1279 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001280 if (channelCount == -1) {
1281 // Try to get channel count from channel mask. From the legacy path,
1282 // only channel mask are logged.
1283 int32_t channelMask = 0;
1284 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1285 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1286 if (channelMask != 0) {
1287 switch (direction) {
1288 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001289 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001290 break;
1291 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001292 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001293 break;
1294 default:
1295 ALOGW("Invalid direction %d", direction);
1296 }
1297 }
1298 }
jiabin515eb092020-11-18 17:55:52 -08001299
1300 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001301 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1302 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001303
1304 std::string perfModeRequestedStr;
1305 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1306 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1307 const auto perfModeRequested =
1308 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1309
jiabin97247ea2021-04-07 00:33:38 +00001310 std::string perfModeActualStr;
1311 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1312 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1313 const auto perfModeActual =
1314 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001315
jiabinc8da9032021-04-28 20:42:36 +00001316 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001317 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001318 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1319 const auto sharingModeActual =
1320 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001321
1322 int32_t xrunCount = -1;
1323 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1324 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1325
jiabin92c9a522021-02-12 22:37:42 +00001326 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001327 // TODO: only routed device id is logged, but no device type
1328
jiabin97247ea2021-04-07 00:33:38 +00001329 std::string formatAppStr;
1330 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001331 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001332 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001333
1334 std::string formatDeviceStr;
1335 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1336 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1337 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1338
jiabin92c9a522021-02-12 22:37:42 +00001339 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001340 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1341 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001342
jiabinc4c331c2021-03-23 17:11:01 +00001343 int32_t sampleRate = 0;
1344 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1345 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1346
1347 std::string contentTypeStr;
1348 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1349 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1350 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1351
jiabinc8da9032021-04-28 20:42:36 +00001352 std::string sharingModeRequestedStr;
1353 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1354 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1355 const auto sharingModeRequested =
1356 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1357
jiabin515eb092020-11-18 17:55:52 -08001358 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001359 << " path:" << path
1360 << " direction:" << direction << "(" << directionStr << ")"
1361 << " frames_per_burst:" << framesPerBurst
1362 << " buffer_size:" << bufferSizeInFrames
1363 << " buffer_capacity:" << bufferCapacityInFrames
1364 << " channel_count:" << channelCount
1365 << " total_frames_transferred:" << totalFramesTransferred
1366 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001367 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001368 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001369 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001370 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001371 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001372 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001373 << " log_session_id: " << logSessionId
1374 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001375 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1376 << " sharing_requested:" << sharingModeRequested
1377 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001378
jiabin92c9a522021-02-12 22:37:42 +00001379 if (mAudioAnalytics.mDeliverStatistics) {
1380 android::util::BytesField bf_serialized(
1381 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1382 const auto result = sendToStatsd(
1383 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001384 , path
1385 , direction
1386 , framesPerBurst
1387 , bufferSizeInFrames
1388 , bufferCapacityInFrames
1389 , channelCount
1390 , totalFramesTransferred
1391 , perfModeRequested
1392 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001393 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001394 , xrunCount
1395 , bf_serialized
1396 , formatApp
1397 , formatDevice
1398 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001399 , sampleRate
1400 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001401 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001402 );
1403 std::stringstream ss;
1404 ss << "result:" << result;
1405 const auto fieldsStr = printFields(AAudioStreamFields,
1406 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001407 , path
1408 , direction
1409 , framesPerBurst
1410 , bufferSizeInFrames
1411 , bufferCapacityInFrames
1412 , channelCount
1413 , totalFramesTransferred
1414 , perfModeRequested
1415 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001416 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001417 , xrunCount
1418 , serializedDeviceTypes.c_str()
1419 , formatApp
1420 , formatDevice
1421 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001422 , sampleRate
1423 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001424 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001425 );
1426 ss << " " << fieldsStr;
1427 std::string str = ss.str();
1428 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001429 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001430 }
jiabin515eb092020-11-18 17:55:52 -08001431}
1432
Andy Hungf4eaa462022-03-09 21:53:09 -08001433// Create new state, typically occurs after an AudioFlinger ctor event.
1434void AudioAnalytics::newState()
1435{
1436 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
1437 *mAnalyticsState.get()));
1438 // Note: get returns shared_ptr temp, whose lifetime is extended
1439 // to end of full expression.
1440 mAnalyticsState->clear(); // TODO: filter the analytics state.
1441 // Perhaps report this.
1442
1443 // Set up a timer to expire the previous audio state to save space.
1444 // Use the transaction log size as a cookie to see if it is the
1445 // same as before. A benign race is possible where a state is cleared early.
1446 const size_t size = mPreviousAnalyticsState->transactionLog().size();
1447 mTimedAction.postIn(
1448 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
1449 if (mPreviousAnalyticsState->transactionLog().size() == size) {
1450 ALOGD("expiring previous audio state after %d seconds.",
1451 PREVIOUS_STATE_EXPIRE_SEC);
1452 mPreviousAnalyticsState->clear(); // removes data from the state.
1453 }
1454 });
1455}
1456
1457void AudioAnalytics::Health::onAudioServerStart(Module module,
1458 const std::shared_ptr<const android::mediametrics::Item> &item)
1459{
1460 const auto nowTime = std::chrono::system_clock::now();
1461 if (module == Module::AUDIOFLINGER) {
1462 {
1463 std::lock_guard lg(mLock);
1464 // reset state on AudioFlinger construction.
1465 // AudioPolicy is created after AudioFlinger.
1466 mAudioFlingerCtorTime = nowTime;
1467 mSimpleLog.log("AudioFlinger ctor");
1468 }
1469 mAudioAnalytics.newState();
1470 return;
1471 }
1472 if (module == Module::AUDIOPOLICY) {
1473 // A start event occurs when audioserver
1474 //
1475 // (1) Starts the first time
1476 // (2) Restarts because of the TimeCheck watchdog
1477 // (3) Restarts not because of the TimeCheck watchdog.
1478 int64_t executionTimeNs = 0;
1479 (void)item->get(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, &executionTimeNs);
1480 const float loadTimeMs = executionTimeNs * 1e-6f;
1481 std::lock_guard lg(mLock);
1482 const int64_t restarts = mStartCount;
1483 if (mStopCount == mStartCount) {
1484 mAudioPolicyCtorTime = nowTime;
1485 ++mStartCount;
1486 if (mStopCount == 0) {
1487 // (1) First time initialization.
1488 ALOGW("%s: (key=%s) AudioPolicy ctor, loadTimeMs:%f",
1489 __func__, item->getKey().c_str(), loadTimeMs);
1490 mSimpleLog.log("AudioPolicy ctor, loadTimeMs:%f", loadTimeMs);
1491 } else {
1492 // (2) Previous failure caught due to TimeCheck. We know how long restart takes.
1493 const float restartMs =
1494 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1495 mAudioFlingerCtorTime - mStopTime).count();
1496 ALOGW("%s: (key=%s) AudioPolicy ctor, "
1497 "restarts:%lld restartMs:%f loadTimeMs:%f",
1498 __func__, item->getKey().c_str(),
1499 (long long)restarts, restartMs, loadTimeMs);
1500 mSimpleLog.log("AudioPolicy ctor restarts:%lld restartMs:%f loadTimeMs:%f",
1501 (long long)restarts, restartMs, loadTimeMs);
1502 }
1503 } else {
1504 // (3) Previous failure is NOT due to TimeCheck, so we don't know the restart time.
1505 // However we can estimate the uptime from the delta time from previous ctor.
1506 const float uptimeMs =
1507 std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1508 nowTime - mAudioFlingerCtorTime).count();
1509 mStopCount = mStartCount;
1510 mAudioPolicyCtorTime = nowTime;
1511 ++mStartCount;
1512
1513 ALOGW("%s: (key=%s) AudioPolicy ctor after uncaught failure, "
1514 "mStartCount:%lld mStopCount:%lld uptimeMs:%f loadTimeMs:%f",
1515 __func__, item->getKey().c_str(),
1516 (long long)mStartCount, (long long)mStopCount, uptimeMs, loadTimeMs);
1517 mSimpleLog.log("AudioPolicy ctor after uncaught failure, "
1518 "restarts:%lld uptimeMs:%f loadTimeMs:%f",
1519 (long long)restarts, uptimeMs, loadTimeMs);
1520 }
1521 }
1522}
1523
1524void AudioAnalytics::Health::onAudioServerTimeout(Module module,
1525 const std::shared_ptr<const android::mediametrics::Item> &item)
1526{
1527 std::string moduleName = getModuleName(module);
1528 int64_t methodCode{};
1529 std::string methodName;
1530 (void)item->get(AMEDIAMETRICS_PROP_METHODCODE, &methodCode);
1531 (void)item->get(AMEDIAMETRICS_PROP_METHODNAME, &methodName);
1532
1533 std::lock_guard lg(mLock);
1534 if (mStopCount >= mStartCount) {
1535 ALOGD("%s: (key=%s) %s timeout %s(%lld) "
1536 "unmatched mStopCount(%lld) >= mStartCount(%lld), ignoring",
1537 __func__, item->getKey().c_str(), moduleName.c_str(),
1538 methodName.c_str(), (long long)methodCode,
1539 (long long)mStopCount, (long long)mStartCount);
1540 return;
1541 }
1542
1543 const int64_t restarts = mStartCount - 1;
1544 ++mStopCount;
1545 mStopTime = std::chrono::system_clock::now();
1546 const float uptimeMs = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(
1547 mStopTime - mAudioFlingerCtorTime).count();
1548 ALOGW("%s: (key=%s) %s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1549 __func__, item->getKey().c_str(), moduleName.c_str(),
1550 methodName.c_str(), (long long)methodCode,
1551 (long long)restarts, uptimeMs);
1552 mSimpleLog.log("%s timeout %s(%lld) restarts:%lld uptimeMs:%f",
1553 moduleName.c_str(), methodName.c_str(), (long long)methodCode,
1554 (long long)restarts, uptimeMs);
1555}
1556
1557std::pair<std::string, int32_t> AudioAnalytics::Health::dump(
1558 int32_t lines, const char *prefix) const
1559{
1560 std::lock_guard lg(mLock);
1561 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1562 size_t n = std::count(s.begin(), s.end(), '\n');
1563 return { s, n };
1564}
1565
Andy Hung05874e82022-08-17 17:27:32 -07001566// Classifies the setting event for statsd (use generated statsd enums.proto constants).
1567static int32_t classifySettingEvent(bool isSetAlready, bool withinBoot) {
1568 if (isSetAlready) {
1569 return util::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_NORMAL;
1570 }
1571 if (withinBoot) {
1572 return util::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_BOOT;
1573 }
1574 return util::MEDIAMETRICS_SPATIALIZER_DEVICE_ENABLED_REPORTED__EVENT__SPATIALIZER_SETTING_EVENT_FIRST;
1575}
1576
Andy Hunge0d43b42022-08-18 19:20:48 -07001577void AudioAnalytics::Spatializer::onEvent(
1578 const std::shared_ptr<const android::mediametrics::Item> &item)
1579{
1580 const auto key = item->getKey();
1581
1582 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER)) return;
1583
1584 const std::string suffix =
1585 key.substr(std::size(AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER) - 1);
1586
1587 std::string eventStr; // optional - find the actual event string.
1588 (void)item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
1589
1590 const size_t delim = suffix.find('.'); // note could use split.
1591 if (delim == suffix.npos) {
1592 // on create with suffix == "0" for the first spatializer effect.
1593
1594 std::string headTrackingModes;
1595 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKINGMODES, &headTrackingModes);
1596
1597 std::string levels;
1598 (void)item->get(AMEDIAMETRICS_PROP_LEVELS, &levels);
1599
1600 std::string modes;
1601 (void)item->get(AMEDIAMETRICS_PROP_MODES, &modes);
1602
Andy Hung05874e82022-08-17 17:27:32 -07001603 std::string channelMasks;
1604 (void)item->get(AMEDIAMETRICS_PROP_CHANNELMASKS, &channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001605
1606 LOG(LOG_LEVEL) << "key:" << key
1607 << " headTrackingModes:" << headTrackingModes
1608 << " levels:" << levels
1609 << " modes:" << modes
Andy Hung05874e82022-08-17 17:27:32 -07001610 << " channelMasks:" << channelMasks
Andy Hunge0d43b42022-08-18 19:20:48 -07001611 ;
1612
1613 const std::vector<int32_t> headTrackingModesVector =
1614 types::vectorFromMap(headTrackingModes, types::getHeadTrackingModeMap());
1615 const std::vector<int32_t> levelsVector =
1616 types::vectorFromMap(levels, types::getSpatializerLevelMap());
1617 const std::vector<int32_t> modesVector =
1618 types::vectorFromMap(modes, types::getSpatializerModeMap());
Andy Hung05874e82022-08-17 17:27:32 -07001619 const std::vector<int64_t> channelMasksVector =
1620 types::channelMaskVectorFromString(channelMasks);
Andy Hunge0d43b42022-08-18 19:20:48 -07001621
Andy Hung05874e82022-08-17 17:27:32 -07001622 const auto [ result, str ] = sendToStatsd(SpatializerCapabilitiesFields,
1623 CONDITION(android::util::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED)
1624 , headTrackingModesVector
1625 , levelsVector
1626 , modesVector
1627 , channelMasksVector
1628 );
1629
1630 mAudioAnalytics.mStatsdLog->log(
1631 android::util::MEDIAMETRICS_SPATIALIZERCAPABILITIES_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001632
1633 std::lock_guard lg(mLock);
Andy Hung05874e82022-08-17 17:27:32 -07001634 if (mFirstCreateTimeNs == 0) {
1635 // Only update the create time once to prevent audioserver restart
1636 // from looking like a boot.
1637 mFirstCreateTimeNs = item->getTimestamp();
1638 }
Andy Hunge0d43b42022-08-18 19:20:48 -07001639 mSimpleLog.log("%s suffix: %s item: %s",
1640 __func__, suffix.c_str(), item->toString().c_str());
1641 } else {
1642 std::string subtype = suffix.substr(0, delim);
1643 if (subtype != "device") return; // not a device.
1644
Andy Hung05874e82022-08-17 17:27:32 -07001645 const std::string deviceType = suffix.substr(std::size("device.") - 1);
Andy Hunge0d43b42022-08-18 19:20:48 -07001646
Andy Hung05874e82022-08-17 17:27:32 -07001647 const int32_t deviceTypeStatsd =
1648 types::lookup<types::AUDIO_DEVICE_INFO_TYPE, int32_t>(deviceType);
1649
1650 std::string address;
1651 (void)item->get(AMEDIAMETRICS_PROP_ADDRESS, &address);
Andy Hunge0d43b42022-08-18 19:20:48 -07001652 std::string enabled;
1653 (void)item->get(AMEDIAMETRICS_PROP_ENABLED, &enabled);
1654 std::string hasHeadTracker;
1655 (void)item->get(AMEDIAMETRICS_PROP_HASHEADTRACKER, &hasHeadTracker);
1656 std::string headTrackerEnabled;
1657 (void)item->get(AMEDIAMETRICS_PROP_HEADTRACKERENABLED, &headTrackerEnabled);
1658
1659 std::lock_guard lg(mLock);
1660
1661 // Validate from our cached state
Andy Hung05874e82022-08-17 17:27:32 -07001662
1663 // Our deviceKey takes the device type and appends the address if any.
1664 // This distinguishes different wireless devices for the purposes of tracking.
1665 std::string deviceKey(deviceType);
1666 deviceKey.append("_").append(address);
1667 DeviceState& deviceState = mDeviceStateMap[deviceKey];
1668
1669 // check whether the settings event is within a certain time of spatializer creation.
1670 const bool withinBoot =
1671 item->getTimestamp() - mFirstCreateTimeNs < kBootDurationThreshold;
Andy Hunge0d43b42022-08-18 19:20:48 -07001672
1673 if (!enabled.empty()) {
1674 if (enabled != deviceState.enabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001675 const int32_t settingEventStatsd =
1676 classifySettingEvent(!deviceState.enabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001677 deviceState.enabled = enabled;
1678 const bool enabledStatsd = enabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001679 const auto [ result, str ] = sendToStatsd(SpatializerDeviceEnabledFields,
1680 CONDITION(android::util::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED)
1681 , deviceTypeStatsd
1682 , settingEventStatsd
1683 , enabledStatsd
1684 );
1685 mAudioAnalytics.mStatsdLog->log(
1686 android::util::MEDIAMETRICS_SPATIALIZERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001687 }
1688 }
1689 if (!hasHeadTracker.empty()) {
1690 if (hasHeadTracker != deviceState.hasHeadTracker) {
Andy Hung05874e82022-08-17 17:27:32 -07001691 const int32_t settingEventStatsd =
1692 classifySettingEvent(!deviceState.hasHeadTracker.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001693 deviceState.hasHeadTracker = hasHeadTracker;
1694 const bool supportedStatsd = hasHeadTracker == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001695 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceSupportedFields,
1696 CONDITION(android::util::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED)
1697 , deviceTypeStatsd
1698 , settingEventStatsd
1699 , supportedStatsd
1700 );
1701 mAudioAnalytics.mStatsdLog->log(
1702 android::util::MEDIAMETRICS_HEADTRACKERDEVICESUPPORTED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001703 }
1704 }
1705 if (!headTrackerEnabled.empty()) {
1706 if (headTrackerEnabled != deviceState.headTrackerEnabled) {
Andy Hung05874e82022-08-17 17:27:32 -07001707 const int32_t settingEventStatsd =
1708 classifySettingEvent(!deviceState.headTrackerEnabled.empty(), withinBoot);
Andy Hunge0d43b42022-08-18 19:20:48 -07001709 deviceState.headTrackerEnabled = headTrackerEnabled;
1710 const bool enabledStatsd = headTrackerEnabled == "true";
Andy Hung05874e82022-08-17 17:27:32 -07001711 const auto [ result, str ] = sendToStatsd(HeadTrackerDeviceEnabledFields,
1712 CONDITION(android::util::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED)
1713 , deviceTypeStatsd
1714 , settingEventStatsd
1715 , enabledStatsd
1716 );
1717 mAudioAnalytics.mStatsdLog->log(
1718 android::util::MEDIAMETRICS_HEADTRACKERDEVICEENABLED_REPORTED, str);
Andy Hunge0d43b42022-08-18 19:20:48 -07001719 }
1720 }
Andy Hung05874e82022-08-17 17:27:32 -07001721 mSimpleLog.log("%s deviceKey: %s item: %s",
1722 __func__, deviceKey.c_str(), item->toString().c_str());
Andy Hunge0d43b42022-08-18 19:20:48 -07001723 }
1724}
1725
1726std::pair<std::string, int32_t> AudioAnalytics::Spatializer::dump(
1727 int32_t lines, const char *prefix) const
1728{
1729 std::lock_guard lg(mLock);
1730 std::string s = mSimpleLog.dumpToString(prefix == nullptr ? "" : prefix, lines);
1731 size_t n = std::count(s.begin(), s.end(), '\n');
1732 return { s, n };
1733}
Andy Hungf4eaa462022-03-09 21:53:09 -08001734
Andy Hung3ab1b322020-05-18 10:47:31 -07001735} // namespace android::mediametrics