blob: aacc2be1f6bfc82e8a8668cf2296b437762d299c [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
243/**
244 * printFields is a helper method that prints the fields and corresponding values
245 * in a human readable style.
246 */
247template <size_t N, typename ...Types>
248std::string printFields(const char * const (& fields)[N], Types ... args)
249{
250 std::stringstream ss;
251 ss << " { ";
252 stringutils::fieldPrint(ss, fields, args...);
253 ss << "}";
254 return ss.str();
255}
256
257/**
258 * sendToStatsd is a helper method that sends the arguments to statsd
259 */
260template <typename ...Types>
261int sendToStatsd(Types ... args)
262{
263 int result = 0;
264
265#ifdef STATSD_ENABLE
266 result = android::util::stats_write(args...);
267#endif
268 return result;
269}
jiabin515eb092020-11-18 17:55:52 -0800270
Andy Hunga629bd12020-06-05 16:03:53 -0700271/**
272 * sendToStatsd is a helper method that sends the arguments to statsd
273 * and returns a pair { result, summary_string }.
274 */
275template <size_t N, typename ...Types>
276std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
277{
278 int result = 0;
279 std::stringstream ss;
280
281#ifdef STATSD_ENABLE
282 result = android::util::stats_write(args...);
283 ss << "result:" << result;
284#endif
285 ss << " { ";
286 stringutils::fieldPrint(ss, fields, args...);
287 ss << "}";
288 return { result, ss.str() };
289}
Andy Hung06f3aba2019-12-03 16:36:42 -0800290
Andy Hung5be90c82021-03-30 14:30:20 -0700291AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700292 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700293 , mStatsdLog(statsdLog)
294 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800295{
Andy Hunga629bd12020-06-05 16:03:53 -0700296 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800297 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800298
299 // Add action to save AnalyticsState if audioserver is restarted.
300 // This triggers on an item of "audio.flinger"
301 // with a property "event" set to "AudioFlinger" (the constructor).
302 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800303 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
304 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800305 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800306 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
307 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800308 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
309 *mAnalyticsState.get()));
310 // Note: get returns shared_ptr temp, whose lifetime is extended
311 // to end of full expression.
312 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800313 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700314
315 // Set up a timer to expire the previous audio state to save space.
316 // Use the transaction log size as a cookie to see if it is the
317 // same as before. A benign race is possible where a state is cleared early.
318 const size_t size = mPreviousAnalyticsState->transactionLog().size();
319 mTimedAction.postIn(
320 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
321 if (mPreviousAnalyticsState->transactionLog().size() == size) {
322 ALOGD("expiring previous audio state after %d seconds.",
323 PREVIOUS_STATE_EXPIRE_SEC);
324 mPreviousAnalyticsState->clear(); // removes data from the state.
325 }
326 });
Andy Hungea186fa2020-01-09 18:13:15 -0800327 }));
328
jiabin97247ea2021-04-07 00:33:38 +0000329 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800330 mActions.addAction(
331 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
332 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
333 std::make_shared<AnalyticsActions::Function>(
334 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
335 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
336 }));
337
jiabin97247ea2021-04-07 00:33:38 +0000338 // Handle legacy aaudio capture stream statistics
339 mActions.addAction(
340 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
341 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
342 std::make_shared<AnalyticsActions::Function>(
343 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
344 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
345 }));
346
jiabin515eb092020-11-18 17:55:52 -0800347 // Handle mmap aaudio stream statistics
348 mActions.addAction(
349 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
350 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
351 std::make_shared<AnalyticsActions::Function>(
352 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
353 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
354 }));
355
Andy Hungea840382020-05-05 21:50:17 -0700356 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800357 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700358 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
359 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800360 std::make_shared<AnalyticsActions::Function>(
361 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700362 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800363 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700364
365 // Handle device use thread statistics
366 mActions.addAction(
367 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
368 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
369 std::make_shared<AnalyticsActions::Function>(
370 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700371 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700372 }));
373
374 // Handle device use track statistics
375 mActions.addAction(
376 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
377 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
378 std::make_shared<AnalyticsActions::Function>(
379 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700380 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700381 }));
382
Andy Hungea840382020-05-05 21:50:17 -0700383
384 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700385
386 // We track connections (not disconnections) for the time to connect.
387 // TODO: consider BT requests in their A2dp service
388 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
389 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
390 // AudioDeviceBroker.postA2dpActiveDeviceChange
391 mActions.addAction(
392 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700393 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700394 std::make_shared<AnalyticsActions::Function>(
395 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
396 mDeviceConnection.a2dpConnected(item);
397 }));
398 // If audio is active, we expect to see a createAudioPatch after the device is connected.
399 mActions.addAction(
400 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
401 std::string("createAudioPatch"),
402 std::make_shared<AnalyticsActions::Function>(
403 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
404 mDeviceConnection.createPatch(item);
405 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800406
Andy Hungea840382020-05-05 21:50:17 -0700407 // Called from BT service
408 mActions.addAction(
409 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
410 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
411 "." AMEDIAMETRICS_PROP_STATE,
412 "connected",
413 std::make_shared<AnalyticsActions::Function>(
414 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
415 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
416 }));
417
Joey Poomarin52989982020-03-05 17:40:49 +0800418 // Handle power usage
419 mActions.addAction(
420 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
421 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
422 std::make_shared<AnalyticsActions::Function>(
423 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
424 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
425 }));
426
427 mActions.addAction(
428 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
429 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
430 std::make_shared<AnalyticsActions::Function>(
431 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
432 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
433 }));
434
435 mActions.addAction(
436 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
437 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
438 std::make_shared<AnalyticsActions::Function>(
439 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
440 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
441 mAudioPowerUsage.checkMode(item);
442 }));
443
444 mActions.addAction(
445 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
446 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
447 std::make_shared<AnalyticsActions::Function>(
448 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
449 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
450 mAudioPowerUsage.checkVoiceVolume(item);
451 }));
452
453 mActions.addAction(
454 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
455 std::string("createAudioPatch"),
456 std::make_shared<AnalyticsActions::Function>(
457 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
458 mAudioPowerUsage.checkCreatePatch(item);
459 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800460}
461
462AudioAnalytics::~AudioAnalytics()
463{
464 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700465 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800466}
467
468status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800469 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800470{
Andy Hungea186fa2020-01-09 18:13:15 -0800471 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800472 status_t status = mAnalyticsState->submit(item, isTrusted);
Andy Hung73dc2f92021-12-07 21:50:04 -0800473
474 // Status is selectively authenticated.
475 processStatus(item);
476
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800477 if (status != NO_ERROR) return status; // may not be permitted.
478
479 // Only if the item was successfully submitted (permission)
480 // do we check triggered actions.
Andy Hung73dc2f92021-12-07 21:50:04 -0800481 processActions(item);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800482 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800483}
484
Andy Hung709b91e2020-04-04 14:23:36 -0700485std::pair<std::string, int32_t> AudioAnalytics::dump(
486 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800487{
488 std::stringstream ss;
489 int32_t ll = lines;
490
491 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700492 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700493 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800494 ll -= l;
495 }
496 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800497 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800498 --ll;
499 }
500 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700501 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700502 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800503 ll -= l;
504 }
Joey Poomarin52989982020-03-05 17:40:49 +0800505
506 if (ll > 0 && prefix == nullptr) {
507 auto [s, l] = mAudioPowerUsage.dump(ll);
508 ss << s;
509 ll -= l;
510 }
Andy Hunga629bd12020-06-05 16:03:53 -0700511
Andy Hung06f3aba2019-12-03 16:36:42 -0800512 return { ss.str(), lines - ll };
513}
514
Andy Hung73dc2f92021-12-07 21:50:04 -0800515void AudioAnalytics::processActions(const std::shared_ptr<const mediametrics::Item>& item)
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800516{
517 auto actions = mActions.getActionsForItem(item); // internally locked.
518 // Execute actions with no lock held.
519 for (const auto& action : actions) {
520 (*action)(item);
521 }
522}
523
Andy Hung73dc2f92021-12-07 21:50:04 -0800524void AudioAnalytics::processStatus(const std::shared_ptr<const mediametrics::Item>& item)
525{
526 int32_t status;
527 if (!item->get(AMEDIAMETRICS_PROP_STATUS, &status)) return;
528
529 // Any record with a status will automatically be added to a heat map.
530 // Standard information.
531 const auto key = item->getKey();
532 const auto uid = item->getUid();
533
534 // from audio.track.10 -> prefix = audio.track, suffix = 10
535 // from audio.track.error -> prefix = audio.track, suffix = error
536 const auto [prefixKey, suffixKey] = stringutils::splitPrefixKey(key);
537
538 std::string message;
539 item->get(AMEDIAMETRICS_PROP_STATUSMESSAGE, &message); // optional
540
541 int32_t subCode = 0; // not used
542 (void)item->get(AMEDIAMETRICS_PROP_STATUSSUBCODE, &subCode); // optional
543
544 std::string eventStr; // optional
545 item->get(AMEDIAMETRICS_PROP_EVENT, &eventStr);
546
547 const std::string statusString = extendedStatusToStatusString(status);
548
549 // Add to the heat map - we automatically track every item's status to see
550 // the types of errors and the frequency of errors.
551 mHeatMap.add(prefixKey, suffixKey, eventStr, statusString, uid, message, subCode);
Andy Hungb8918b52021-12-14 22:15:40 -0800552
Andy Hung44326582022-01-11 17:27:09 -0800553 // Certain keys/event pairs are sent to statsd. If we get a match (true) we return early.
554 if (reportAudioRecordStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
555 if (reportAudioTrackStatus(item, key, eventStr, statusString, uid, message, subCode)) return;
556}
557
558bool AudioAnalytics::reportAudioRecordStatus(
559 const std::shared_ptr<const mediametrics::Item>& item,
560 const std::string& key, const std::string& eventStr,
561 const std::string& statusString, uid_t uid, const std::string& message,
562 int32_t subCode) const
563{
Andy Hungb8918b52021-12-14 22:15:40 -0800564 // Note that the prefixes often end with a '.' so we use startsWith.
Andy Hung44326582022-01-11 17:27:09 -0800565 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)) return false;
566 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
567 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
568
569 // currently we only send create status events.
570 const int32_t event = android::util::
571 MEDIAMETRICS_AUDIO_RECORD_STATUS_REPORTED__EVENT__AUDIO_RECORD_EVENT_CREATE;
572
573 // The following fields should all be present in a create event.
574 std::string flagsStr;
575 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
576 "%s: %s missing %s field", __func__,
577 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
578 const auto flags = types::lookup<types::INPUT_FLAG, int32_t>(flagsStr);
579
580 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
581
582 std::string sourceStr;
583 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SOURCE, &sourceStr),
584 "%s: %s missing %s field",
585 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SOURCE);
586 const int32_t source = types::lookup<types::SOURCE_TYPE, int32_t>(sourceStr);
587
588 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
589
590 std::string encodingStr;
591 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
592 "%s: %s missing %s field",
593 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_ENCODING);
594 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
595
596 int32_t channelMask = 0;
597 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
598 "%s: %s missing %s field",
599 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_CHANNELMASK);
600 int32_t frameCount = 0;
601 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
602 "%s: %s missing %s field",
603 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_FRAMECOUNT);
604 int32_t sampleRate = 0;
605 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
606 "%s: %s missing %s field",
607 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD, AMEDIAMETRICS_PROP_SAMPLERATE);
608
609 const auto [ result, str ] = sendToStatsd(AudioRecordStatusFields,
610 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED)
611 , atom_status
612 , message.c_str()
613 , subCode
614 , uid
615 , event
616 , flags
617 , source
618 , encoding
619 , (int64_t)channelMask
620 , frameCount
621 , sampleRate
622 );
623 ALOGV("%s: statsd %s", __func__, str.c_str());
624 mStatsdLog->log(android::util::MEDIAMETRICS_AUDIORECORDSTATUS_REPORTED, str);
625 return true;
626 }
627 return false;
628}
629
630bool AudioAnalytics::reportAudioTrackStatus(
631 const std::shared_ptr<const mediametrics::Item>& item,
632 const std::string& key, const std::string& eventStr,
633 const std::string& statusString, uid_t uid, const std::string& message,
634 int32_t subCode) const
635{
636 // Note that the prefixes often end with a '.' so we use startsWith.
637 if (!startsWith(key, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)) return false;
638 if (eventStr == AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE) {
Andy Hungb8918b52021-12-14 22:15:40 -0800639 const int atom_status = types::lookup<types::STATUS, int32_t>(statusString);
640
641 // currently we only send create status events.
Andy Hungcb40b982022-01-31 20:08:25 -0800642 const int32_t event = android::util::
643 MEDIAMETRICS_AUDIO_TRACK_STATUS_REPORTED__EVENT__AUDIO_TRACK_EVENT_CREATE;
Andy Hungb8918b52021-12-14 22:15:40 -0800644
645 // The following fields should all be present in a create event.
646 std::string flagsStr;
647 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ORIGINALFLAGS, &flagsStr),
648 "%s: %s missing %s field",
649 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ORIGINALFLAGS);
650 const auto flags = types::lookup<types::OUTPUT_FLAG, int32_t>(flagsStr);
651
652 // AMEDIAMETRICS_PROP_SESSIONID omitted from atom
653
654 std::string contentTypeStr;
655 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr),
656 "%s: %s missing %s field",
657 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CONTENTTYPE);
658 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
659
660 std::string usageStr;
661 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_USAGE, &usageStr),
662 "%s: %s missing %s field",
663 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_USAGE);
664 const auto usage = types::lookup<types::USAGE, int32_t>(usageStr);
665
666 // AMEDIAMETRICS_PROP_SELECTEDDEVICEID omitted from atom
667
668 std::string encodingStr;
669 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_ENCODING, &encodingStr),
670 "%s: %s missing %s field",
671 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_ENCODING);
672 const auto encoding = types::lookup<types::ENCODING, int32_t>(encodingStr);
673
674 int32_t channelMask = 0;
675 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask),
676 "%s: %s missing %s field",
677 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_CHANNELMASK);
678 int32_t frameCount = 0;
679 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount),
680 "%s: %s missing %s field",
681 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_FRAMECOUNT);
682 int32_t sampleRate = 0;
683 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate),
684 "%s: %s missing %s field",
685 __func__, AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_SAMPLERATE);
686 double speed = 0.f; // default is 1.f
687 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &speed),
688 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800689 __func__,
690 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_SPEED);
Andy Hungb8918b52021-12-14 22:15:40 -0800691 double pitch = 0.f; // default is 1.f
692 ALOGD_IF(!item->get(AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &pitch),
693 "%s: %s missing %s field",
Andy Hung44326582022-01-11 17:27:09 -0800694 __func__,
695 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK, AMEDIAMETRICS_PROP_PLAYBACK_PITCH);
Andy Hungb8918b52021-12-14 22:15:40 -0800696 const auto [ result, str ] = sendToStatsd(AudioTrackStatusFields,
697 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED)
698 , atom_status
699 , message.c_str()
700 , subCode
701 , uid
702 , event
703 , flags
704 , contentType
705 , usage
706 , encoding
707 , (int64_t)channelMask
708 , frameCount
709 , sampleRate
710 , (float)speed
711 , (float)pitch
712 );
713 ALOGV("%s: statsd %s", __func__, str.c_str());
714 mStatsdLog->log(android::util::MEDIAMETRICS_AUDIOTRACKSTATUS_REPORTED, str);
Andy Hung44326582022-01-11 17:27:09 -0800715 return true;
Andy Hungb8918b52021-12-14 22:15:40 -0800716 }
Andy Hung44326582022-01-11 17:27:09 -0800717 return false;
Andy Hung73dc2f92021-12-07 21:50:04 -0800718}
719
Andy Hungea186fa2020-01-09 18:13:15 -0800720// HELPER METHODS
721
722std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
723{
724 int32_t threadId_int32{};
725 if (mAnalyticsState->timeMachine().get(
726 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
727 return {};
728 }
729 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
730}
731
Andy Hungce9b6632020-04-28 20:15:17 -0700732// DeviceUse helper class.
733void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700734 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700735 const std::string& key = item->getKey();
736 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700737 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
738 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
739 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700740 - 1);
741 // deliver statistics
742 int64_t deviceTimeNs = 0;
743 mAudioAnalytics.mAnalyticsState->timeMachine().get(
744 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
745 std::string encoding;
746 mAudioAnalytics.mAnalyticsState->timeMachine().get(
747 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
748 int32_t frameCount = 0;
749 mAudioAnalytics.mAnalyticsState->timeMachine().get(
750 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700751 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700752 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700753 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700754 int32_t intervalCount = 0;
755 mAudioAnalytics.mAnalyticsState->timeMachine().get(
756 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700757 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700758 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700759 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700760 int32_t sampleRate = 0;
761 mAudioAnalytics.mAnalyticsState->timeMachine().get(
762 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700763 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700764 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700765 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700766
Andy Hungea840382020-05-05 21:50:17 -0700767 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700768 // Accumulate the bit flags for input and output devices.
769 std::stringstream oss;
770 long_enum_type_t outputDeviceBits{};
771 { // compute outputDevices
772 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700773 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700774 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
775 oss << device;
776 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700777 }
778 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700779 const std::string outputDevices = oss.str();
780
781 std::stringstream iss;
782 long_enum_type_t inputDeviceBits{};
783 { // compute inputDevices
784 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
785 for (const auto& [device, addr] : devaddrvec) {
786 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
787 iss << device;
788 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
789 }
790 }
791 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700792
793 // Get connected device name if from bluetooth.
794 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700795
796 std::string inputDeviceNames; // not filled currently.
797 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700798 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
799 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700800 outputDeviceNames = SUPPRESSED;
801#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700802 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700803 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700804 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700805 stringutils::replace(outputDeviceNames, "|", '?');
806 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
807 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
808 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700809#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700810 }
811
Andy Hungea840382020-05-05 21:50:17 -0700812 switch (itemType) {
813 case RECORD: {
814 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700815 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
816 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700817
Andy Hungea840382020-05-05 21:50:17 -0700818 std::string packageName;
819 int64_t versionCode = 0;
820 int32_t uid = -1;
821 mAudioAnalytics.mAnalyticsState->timeMachine().get(
822 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
823 if (uid != -1) {
824 std::tie(packageName, versionCode) =
825 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
826 }
827
828 int32_t selectedDeviceId = 0;
829 mAudioAnalytics.mAnalyticsState->timeMachine().get(
830 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
831 std::string source;
832 mAudioAnalytics.mAnalyticsState->timeMachine().get(
833 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800834 // Android S
835 std::string logSessionId;
836 mAudioAnalytics.mAnalyticsState->timeMachine().get(
837 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700838
Andy Hung1ea842e2020-05-18 10:47:31 -0700839 const auto callerNameForStats =
840 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
841 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
842 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
843 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800844 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700845 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700846
Andy Hunga629bd12020-06-05 16:03:53 -0700847 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700848 << " id:" << id
849 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700850 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700851 << " deviceTimeNs:" << deviceTimeNs
852 << " encoding:" << encoding << "(" << encodingForStats
853 << ") frameCount:" << frameCount
854 << " intervalCount:" << intervalCount
855 << " sampleRate:" << sampleRate
856 << " flags:" << flags << "(" << flagsForStats
857 << ") packageName:" << packageName
858 << " selectedDeviceId:" << selectedDeviceId
859 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800860 << ") source:" << source << "(" << sourceForStats
861 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
862 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700863 if (clientCalled // only log if client app called AudioRecord.
864 && mAudioAnalytics.mDeliverStatistics) {
865 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
866 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700867 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700868 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700869 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700870 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700871 , frameCount
872 , intervalCount
873 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700874 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700875
876 , packageName.c_str()
877 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700878 , ENUM_EXTRACT(callerNameForStats)
879 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800880 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700881 );
Andy Hunga629bd12020-06-05 16:03:53 -0700882 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700883 mAudioAnalytics.mStatsdLog->log(
884 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700885 }
Andy Hungea840382020-05-05 21:50:17 -0700886 } break;
887 case THREAD: {
888 std::string type;
889 mAudioAnalytics.mAnalyticsState->timeMachine().get(
890 key, AMEDIAMETRICS_PROP_TYPE, &type);
891 int32_t underrun = 0; // zero for record types
892 mAudioAnalytics.mAnalyticsState->timeMachine().get(
893 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700894
895 const bool isInput = types::isInputThreadType(type);
896 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
897 const auto flagsForStats =
898 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
899 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
900 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
901
Andy Hunga629bd12020-06-05 16:03:53 -0700902 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700903 << " id:" << id
904 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
905 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700906 << ") inputDeviceNames:" << inputDeviceNames
907 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700908 << " deviceTimeNs:" << deviceTimeNs
909 << " encoding:" << encoding << "(" << encodingForStats
910 << ") frameCount:" << frameCount
911 << " intervalCount:" << intervalCount
912 << " sampleRate:" << sampleRate
913 << " underrun:" << underrun
914 << " flags:" << flags << "(" << flagsForStats
915 << ") type:" << type << "(" << typeForStats
916 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700917 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700918 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
919 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
920 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
921 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700922 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700923 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700924 , frameCount
925 , intervalCount
926 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700927 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700928 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700929 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700930 );
Andy Hunga629bd12020-06-05 16:03:53 -0700931 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700932 mAudioAnalytics.mStatsdLog->log(
933 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700934 }
Andy Hungea840382020-05-05 21:50:17 -0700935 } break;
936 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700937 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700938 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
939 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
940
Andy Hungce9b6632020-04-28 20:15:17 -0700941 std::string contentType;
942 mAudioAnalytics.mAnalyticsState->timeMachine().get(
943 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
944 double deviceLatencyMs = 0.;
945 mAudioAnalytics.mAnalyticsState->timeMachine().get(
946 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
947 double deviceStartupMs = 0.;
948 mAudioAnalytics.mAnalyticsState->timeMachine().get(
949 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
950 double deviceVolume = 0.;
951 mAudioAnalytics.mAnalyticsState->timeMachine().get(
952 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
953 std::string packageName;
954 int64_t versionCode = 0;
955 int32_t uid = -1;
956 mAudioAnalytics.mAnalyticsState->timeMachine().get(
957 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
958 if (uid != -1) {
959 std::tie(packageName, versionCode) =
960 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
961 }
962 double playbackPitch = 0.;
963 mAudioAnalytics.mAnalyticsState->timeMachine().get(
964 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
965 double playbackSpeed = 0.;
966 mAudioAnalytics.mAnalyticsState->timeMachine().get(
967 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
968 int32_t selectedDeviceId = 0;
969 mAudioAnalytics.mAnalyticsState->timeMachine().get(
970 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700971 std::string streamType;
972 mAudioAnalytics.mAnalyticsState->timeMachine().get(
973 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700974 std::string traits;
975 mAudioAnalytics.mAnalyticsState->timeMachine().get(
976 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700977 int32_t underrun = 0;
978 mAudioAnalytics.mAnalyticsState->timeMachine().get(
979 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700980 std::string usage;
981 mAudioAnalytics.mAnalyticsState->timeMachine().get(
982 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800983 // Android S
984 std::string logSessionId;
985 mAudioAnalytics.mAnalyticsState->timeMachine().get(
986 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700987
Andy Hung1ea842e2020-05-18 10:47:31 -0700988 const auto callerNameForStats =
989 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
990 const auto contentTypeForStats =
991 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
992 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
993 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
994 const auto streamTypeForStats =
995 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700996 const auto traitsForStats =
997 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700998 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800999 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -07001000 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -07001001
Andy Hunga629bd12020-06-05 16:03:53 -07001002 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001003 << " id:" << id
1004 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001005 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -07001006 << " deviceTimeNs:" << deviceTimeNs
1007 << " encoding:" << encoding << "(" << encodingForStats
1008 << ") frameCount:" << frameCount
1009 << " intervalCount:" << intervalCount
1010 << " sampleRate:" << sampleRate
1011 << " underrun:" << underrun
1012 << " flags:" << flags << "(" << flagsForStats
1013 << ") callerName:" << callerName << "(" << callerNameForStats
1014 << ") contentType:" << contentType << "(" << contentTypeForStats
1015 << ") deviceLatencyMs:" << deviceLatencyMs
1016 << " deviceStartupMs:" << deviceStartupMs
1017 << " deviceVolume:" << deviceVolume
1018 << " packageName:" << packageName
1019 << " playbackPitch:" << playbackPitch
1020 << " playbackSpeed:" << playbackSpeed
1021 << " selectedDeviceId:" << selectedDeviceId
1022 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -07001023 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001024 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -08001025 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -07001026 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -07001027 if (clientCalled // only log if client app called AudioTracks
1028 && mAudioAnalytics.mDeliverStatistics) {
1029 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
1030 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001031 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001032 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001033 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -07001034 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001035 , frameCount
1036 , intervalCount
1037 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -07001038 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -07001039 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -07001040 , packageName.c_str()
1041 , (float)deviceLatencyMs
1042 , (float)deviceStartupMs
1043 , (float)deviceVolume
1044 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -07001045 , ENUM_EXTRACT(streamTypeForStats)
1046 , ENUM_EXTRACT(usageForStats)
1047 , ENUM_EXTRACT(contentTypeForStats)
1048 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -07001049 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -08001050 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -07001051 );
Andy Hunga629bd12020-06-05 16:03:53 -07001052 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001053 mAudioAnalytics.mStatsdLog->log(
1054 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -07001055 }
Andy Hungea840382020-05-05 21:50:17 -07001056 } break;
Andy Hungce9b6632020-04-28 20:15:17 -07001057 }
1058
1059 // Report this as needed.
1060 if (isBluetooth) {
1061 // report this for Bluetooth
1062 }
1063}
1064
1065// DeviceConnection helper class.
1066void AudioAnalytics::DeviceConnection::a2dpConnected(
1067 const std::shared_ptr<const android::mediametrics::Item> &item) {
1068 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -07001069 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -07001070 {
1071 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001072 mA2dpConnectionServiceNs = atNs;
1073 ++mA2dpConnectionServices;
1074
1075 if (mA2dpConnectionRequestNs == 0) {
1076 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1077 }
1078 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -07001079 }
1080 std::string name;
1081 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001082 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
1083 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -07001084}
1085
1086void AudioAnalytics::DeviceConnection::createPatch(
1087 const std::shared_ptr<const android::mediametrics::Item> &item) {
1088 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001089 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -07001090 const std::string& key = item->getKey();
1091 std::string outputDevices;
1092 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -07001093 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -07001094 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -07001095 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -07001096 if (mA2dpConnectionRequestNs == 0) {
1097 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -07001098 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -07001099 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -07001100 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -07001101 }
Andy Hung1ea842e2020-05-18 10:47:31 -07001102
Andy Hungea840382020-05-05 21:50:17 -07001103 mA2dpConnectionRequestNs = 0;
1104 mA2dpConnectionServiceNs = 0;
1105 ++mA2dpConnectionSuccesses;
1106
Andy Hungc14ee142021-03-10 16:39:02 -08001107 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -07001108
1109 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1110 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1111
Andy Hunga629bd12020-06-05 16:03:53 -07001112 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -07001113 << " A2DP SUCCESS"
1114 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -07001115 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -07001116 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -07001117 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -07001118 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -07001119
1120 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1121 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001122 , ENUM_EXTRACT(inputDeviceBits)
1123 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001124 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001125 , types::DEVICE_CONNECTION_RESULT_SUCCESS
1126 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -07001127 , /* connection_count */ 1
1128 );
Andy Hunga629bd12020-06-05 16:03:53 -07001129 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001130 mAudioAnalytics.mStatsdLog->log(
1131 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001132 }
Andy Hungce9b6632020-04-28 20:15:17 -07001133 }
1134}
1135
Andy Hungea840382020-05-05 21:50:17 -07001136// Called through AudioManager when the BT service wants to enable
1137void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
1138 const std::shared_ptr<const android::mediametrics::Item> &item) {
1139 const int64_t atNs = item->getTimestamp();
1140 const std::string& key = item->getKey();
1141 std::string state;
1142 item->get(AMEDIAMETRICS_PROP_STATE, &state);
1143 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -07001144
1145 std::string name;
1146 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -07001147 {
1148 std::lock_guard l(mLock);
1149 mA2dpConnectionRequestNs = atNs;
1150 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -07001151 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -07001152 }
Andy Hunga629bd12020-06-05 16:03:53 -07001153 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
1154 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -07001155 // TODO: attempt to cancel a timed event, rather than let it expire.
1156 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
1157}
1158
Andy Hungce9b6632020-04-28 20:15:17 -07001159void AudioAnalytics::DeviceConnection::expire() {
1160 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -07001161 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -07001162
Andy Hung1ea842e2020-05-18 10:47:31 -07001163 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -07001164 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
1165 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
1166
Andy Hungea840382020-05-05 21:50:17 -07001167 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -07001168 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -07001169
Andy Hunga629bd12020-06-05 16:03:53 -07001170 LOG(LOG_LEVEL) << "A2DP CANCEL"
1171 << " outputDevices:" << outputDeviceBits
1172 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001173 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001174 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1175 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001176 , ENUM_EXTRACT(inputDeviceBits)
1177 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001178 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001179 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -07001180 , /* connection_time_ms */ 0.f
1181 , /* connection_count */ 1
1182 );
Andy Hunga629bd12020-06-05 16:03:53 -07001183 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001184 mAudioAnalytics.mStatsdLog->log(
1185 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001186 }
Andy Hungea840382020-05-05 21:50:17 -07001187 return;
1188 }
1189
1190 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
1191 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -07001192 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -07001193 mA2dpConnectionRequestNs = 0;
1194 mA2dpConnectionServiceNs = 0;
1195 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -07001196
Andy Hunga629bd12020-06-05 16:03:53 -07001197 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
1198 << " outputDevices:" << outputDeviceBits
1199 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -07001200 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -07001201 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
1202 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -07001203 , ENUM_EXTRACT(inputDeviceBits)
1204 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -07001205 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -07001206 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -07001207 , /* connection_time_ms */ 0.f
1208 , /* connection_count */ 1
1209 );
Andy Hunga629bd12020-06-05 16:03:53 -07001210 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001211 mAudioAnalytics.mStatsdLog->log(
1212 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -07001213 }
Andy Hungce9b6632020-04-28 20:15:17 -07001214}
1215
jiabin515eb092020-11-18 17:55:52 -08001216void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
1217 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
1218 const std::string& key = item->getKey();
1219
jiabin515eb092020-11-18 17:55:52 -08001220 std::string directionStr;
1221 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1222 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
1223 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
1224
1225 int32_t framesPerBurst = -1;
1226 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1227 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
1228
1229 int32_t bufferSizeInFrames = -1;
1230 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1231 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
1232
1233 int32_t bufferCapacityInFrames = -1;
1234 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1235 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
1236
1237 int32_t channelCount = -1;
1238 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1239 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +00001240 if (channelCount == -1) {
1241 // Try to get channel count from channel mask. From the legacy path,
1242 // only channel mask are logged.
1243 int32_t channelMask = 0;
1244 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1245 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
1246 if (channelMask != 0) {
1247 switch (direction) {
1248 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001249 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001250 break;
1251 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -08001252 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabinfbf20302021-07-28 22:15:01 +00001253 break;
1254 default:
1255 ALOGW("Invalid direction %d", direction);
1256 }
1257 }
1258 }
jiabin515eb092020-11-18 17:55:52 -08001259
1260 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +00001261 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1262 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -08001263
1264 std::string perfModeRequestedStr;
1265 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1266 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
1267 const auto perfModeRequested =
1268 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
1269
jiabin97247ea2021-04-07 00:33:38 +00001270 std::string perfModeActualStr;
1271 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1272 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
1273 const auto perfModeActual =
1274 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001275
jiabinc8da9032021-04-28 20:42:36 +00001276 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -08001277 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001278 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1279 const auto sharingModeActual =
1280 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001281
1282 int32_t xrunCount = -1;
1283 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1284 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1285
jiabin92c9a522021-02-12 22:37:42 +00001286 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001287 // TODO: only routed device id is logged, but no device type
1288
jiabin97247ea2021-04-07 00:33:38 +00001289 std::string formatAppStr;
1290 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001291 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001292 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001293
1294 std::string formatDeviceStr;
1295 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1296 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1297 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1298
jiabin92c9a522021-02-12 22:37:42 +00001299 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001300 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1301 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001302
jiabinc4c331c2021-03-23 17:11:01 +00001303 int32_t sampleRate = 0;
1304 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1305 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1306
1307 std::string contentTypeStr;
1308 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1309 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1310 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1311
jiabinc8da9032021-04-28 20:42:36 +00001312 std::string sharingModeRequestedStr;
1313 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1314 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1315 const auto sharingModeRequested =
1316 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1317
jiabin515eb092020-11-18 17:55:52 -08001318 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001319 << " path:" << path
1320 << " direction:" << direction << "(" << directionStr << ")"
1321 << " frames_per_burst:" << framesPerBurst
1322 << " buffer_size:" << bufferSizeInFrames
1323 << " buffer_capacity:" << bufferCapacityInFrames
1324 << " channel_count:" << channelCount
1325 << " total_frames_transferred:" << totalFramesTransferred
1326 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001327 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001328 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001329 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001330 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001331 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001332 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001333 << " log_session_id: " << logSessionId
1334 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001335 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1336 << " sharing_requested:" << sharingModeRequested
1337 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001338
jiabin92c9a522021-02-12 22:37:42 +00001339 if (mAudioAnalytics.mDeliverStatistics) {
1340 android::util::BytesField bf_serialized(
1341 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1342 const auto result = sendToStatsd(
1343 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001344 , path
1345 , direction
1346 , framesPerBurst
1347 , bufferSizeInFrames
1348 , bufferCapacityInFrames
1349 , channelCount
1350 , totalFramesTransferred
1351 , perfModeRequested
1352 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001353 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001354 , xrunCount
1355 , bf_serialized
1356 , formatApp
1357 , formatDevice
1358 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001359 , sampleRate
1360 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001361 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001362 );
1363 std::stringstream ss;
1364 ss << "result:" << result;
1365 const auto fieldsStr = printFields(AAudioStreamFields,
1366 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001367 , path
1368 , direction
1369 , framesPerBurst
1370 , bufferSizeInFrames
1371 , bufferCapacityInFrames
1372 , channelCount
1373 , totalFramesTransferred
1374 , perfModeRequested
1375 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001376 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001377 , xrunCount
1378 , serializedDeviceTypes.c_str()
1379 , formatApp
1380 , formatDevice
1381 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001382 , sampleRate
1383 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001384 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001385 );
1386 ss << " " << fieldsStr;
1387 std::string str = ss.str();
1388 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001389 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001390 }
jiabin515eb092020-11-18 17:55:52 -08001391}
1392
Andy Hung3ab1b322020-05-18 10:47:31 -07001393} // namespace android::mediametrics