blob: 2d0d2f49c0c7a2bf53a2d0def2facc6928bba180 [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 Hungce9b6632020-04-28 20:15:17 -070024#include <audio_utils/clock.h> // clock conversions
Andy Hung1ea842e2020-05-18 10:47:31 -070025#include <cutils/properties.h>
Andy Hungce9b6632020-04-28 20:15:17 -070026#include <statslog.h> // statsd
jiabina2202852021-07-28 22:15:01 +000027#include <system/audio.h>
Andy Hung06f3aba2019-12-03 16:36:42 -080028
Andy Hung1ea842e2020-05-18 10:47:31 -070029#include "AudioTypes.h" // string to int conversions
30#include "MediaMetricsService.h" // package info
31#include "StringUtils.h"
32
33#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
34
Andy Hunga629bd12020-06-05 16:03:53 -070035namespace android::mediametrics {
Andy Hung1ea842e2020-05-18 10:47:31 -070036
Andy Hunga629bd12020-06-05 16:03:53 -070037// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
Andy Hunga0a5ad22020-06-12 09:30:34 -070038#define STATSD_ENABLE
Andy Hung1ea842e2020-05-18 10:47:31 -070039
Andy Hunga629bd12020-06-05 16:03:53 -070040#ifdef STATSD_ENABLE
41#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
Andy Hung1ea842e2020-05-18 10:47:31 -070042#else
Andy Hunga629bd12020-06-05 16:03:53 -070043#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
Andy Hung1ea842e2020-05-18 10:47:31 -070044#endif
45
Andy Hunga629bd12020-06-05 16:03:53 -070046// Maximum length of a device name.
Andy Hung3deef2b2020-07-17 12:58:54 -070047// static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
Andy Hung06f3aba2019-12-03 16:36:42 -080048
Andy Hunga629bd12020-06-05 16:03:53 -070049// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
50static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
51
52// derive types based on integer or strings.
53using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
54using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
55
56// Convert std::string to char *
57template <typename T>
58auto ENUM_EXTRACT(const T& x) {
59 if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
60 return x.c_str();
61 } else {
62 return x;
63 }
64}
65
66static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
67
Andy Hungb18f5062020-06-18 23:10:08 -070068static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
69
Andy Hung3deef2b2020-07-17 12:58:54 -070070static constexpr const char * SUPPRESSED = "SUPPRESSED";
71
Andy Hunga629bd12020-06-05 16:03:53 -070072/*
73 * For logging purposes, we list all of the MediaMetrics atom fields,
74 * which can then be associated with consecutive arguments to the statsd write.
75 */
76
77static constexpr const char * const AudioRecordDeviceUsageFields[] = {
78 "mediametrics_audiorecorddeviceusage_reported", // proto number
79 "devices",
80 "device_names",
81 "device_time_nanos",
82 "encoding",
83 "frame_count",
84 "interval_count",
85 "sample_rate",
86 "flags",
87 "package_name",
88 "selected_device_id",
89 "caller",
90 "source",
Andy Hungcbcfaa22021-02-23 13:54:49 -080091 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -070092};
93
94static constexpr const char * const AudioThreadDeviceUsageFields[] = {
95 "mediametrics_audiothreaddeviceusage_reported",
96 "devices",
97 "device_names",
98 "device_time_nanos",
99 "encoding",
100 "frame_count",
101 "interval_count",
102 "sample_rate",
103 "flags",
104 "xruns",
105 "type",
106};
107
108static constexpr const char * const AudioTrackDeviceUsageFields[] = {
109 "mediametrics_audiotrackdeviceusage_reported",
110 "devices",
111 "device_names",
112 "device_time_nanos",
113 "encoding",
114 "frame_count",
115 "interval_count",
116 "sample_rate",
117 "flags",
118 "xruns",
119 "package_name",
120 "device_latency_millis",
121 "device_startup_millis",
122 "device_volume",
123 "selected_device_id",
124 "stream_type",
125 "usage",
126 "content_type",
127 "caller",
128 "traits",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800129 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700130};
131
132static constexpr const char * const AudioDeviceConnectionFields[] = {
133 "mediametrics_audiodeviceconnection_reported",
134 "input_devices",
135 "output_devices",
136 "device_names",
137 "result",
138 "time_to_connect_millis",
139 "connection_count",
140};
141
jiabin92c9a522021-02-12 22:37:42 +0000142static constexpr const char * const AAudioStreamFields[] {
143 "mediametrics_aaudiostream_reported",
jiabin92c9a522021-02-12 22:37:42 +0000144 "path",
145 "direction",
146 "frames_per_burst",
147 "buffer_size",
148 "buffer_capacity",
149 "channel_count",
150 "total_frames_transferred",
151 "perf_mode_requested",
152 "perf_mode_actual",
153 "sharing",
154 "xrun_count",
155 "device_type",
156 "format_app",
157 "format_device",
158 "log_session_id",
jiabinc4c331c2021-03-23 17:11:01 +0000159 "sample_rate",
160 "content_type",
jiabinc8da9032021-04-28 20:42:36 +0000161 "sharing_requested",
jiabin92c9a522021-02-12 22:37:42 +0000162};
163
164/**
165 * printFields is a helper method that prints the fields and corresponding values
166 * in a human readable style.
167 */
168template <size_t N, typename ...Types>
169std::string printFields(const char * const (& fields)[N], Types ... args)
170{
171 std::stringstream ss;
172 ss << " { ";
173 stringutils::fieldPrint(ss, fields, args...);
174 ss << "}";
175 return ss.str();
176}
177
178/**
179 * sendToStatsd is a helper method that sends the arguments to statsd
180 */
181template <typename ...Types>
182int sendToStatsd(Types ... args)
183{
184 int result = 0;
185
186#ifdef STATSD_ENABLE
187 result = android::util::stats_write(args...);
188#endif
189 return result;
190}
jiabin515eb092020-11-18 17:55:52 -0800191
Andy Hunga629bd12020-06-05 16:03:53 -0700192/**
193 * sendToStatsd is a helper method that sends the arguments to statsd
194 * and returns a pair { result, summary_string }.
195 */
196template <size_t N, typename ...Types>
197std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
198{
199 int result = 0;
200 std::stringstream ss;
201
202#ifdef STATSD_ENABLE
203 result = android::util::stats_write(args...);
204 ss << "result:" << result;
205#endif
206 ss << " { ";
207 stringutils::fieldPrint(ss, fields, args...);
208 ss << "}";
209 return { result, ss.str() };
210}
Andy Hung06f3aba2019-12-03 16:36:42 -0800211
Andy Hung5be90c82021-03-30 14:30:20 -0700212AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700213 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700214 , mStatsdLog(statsdLog)
215 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800216{
Andy Hunga629bd12020-06-05 16:03:53 -0700217 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800218 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800219
220 // Add action to save AnalyticsState if audioserver is restarted.
221 // This triggers on an item of "audio.flinger"
222 // with a property "event" set to "AudioFlinger" (the constructor).
223 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800224 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
225 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800226 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800227 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
228 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800229 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
230 *mAnalyticsState.get()));
231 // Note: get returns shared_ptr temp, whose lifetime is extended
232 // to end of full expression.
233 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800234 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700235
236 // Set up a timer to expire the previous audio state to save space.
237 // Use the transaction log size as a cookie to see if it is the
238 // same as before. A benign race is possible where a state is cleared early.
239 const size_t size = mPreviousAnalyticsState->transactionLog().size();
240 mTimedAction.postIn(
241 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
242 if (mPreviousAnalyticsState->transactionLog().size() == size) {
243 ALOGD("expiring previous audio state after %d seconds.",
244 PREVIOUS_STATE_EXPIRE_SEC);
245 mPreviousAnalyticsState->clear(); // removes data from the state.
246 }
247 });
Andy Hungea186fa2020-01-09 18:13:15 -0800248 }));
249
jiabin97247ea2021-04-07 00:33:38 +0000250 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800251 mActions.addAction(
252 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
253 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
254 std::make_shared<AnalyticsActions::Function>(
255 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
256 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
257 }));
258
jiabin97247ea2021-04-07 00:33:38 +0000259 // Handle legacy aaudio capture stream statistics
260 mActions.addAction(
261 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
262 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
263 std::make_shared<AnalyticsActions::Function>(
264 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
265 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
266 }));
267
jiabin515eb092020-11-18 17:55:52 -0800268 // Handle mmap aaudio stream statistics
269 mActions.addAction(
270 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
271 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
272 std::make_shared<AnalyticsActions::Function>(
273 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
274 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
275 }));
276
Andy Hungea840382020-05-05 21:50:17 -0700277 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800278 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700279 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
280 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800281 std::make_shared<AnalyticsActions::Function>(
282 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700283 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800284 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700285
286 // Handle device use thread statistics
287 mActions.addAction(
288 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
289 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
290 std::make_shared<AnalyticsActions::Function>(
291 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700292 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700293 }));
294
295 // Handle device use track statistics
296 mActions.addAction(
297 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
298 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
299 std::make_shared<AnalyticsActions::Function>(
300 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700301 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700302 }));
303
Andy Hungea840382020-05-05 21:50:17 -0700304
305 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700306
307 // We track connections (not disconnections) for the time to connect.
308 // TODO: consider BT requests in their A2dp service
309 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
310 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
311 // AudioDeviceBroker.postA2dpActiveDeviceChange
312 mActions.addAction(
313 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700314 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700315 std::make_shared<AnalyticsActions::Function>(
316 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
317 mDeviceConnection.a2dpConnected(item);
318 }));
319 // If audio is active, we expect to see a createAudioPatch after the device is connected.
320 mActions.addAction(
321 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
322 std::string("createAudioPatch"),
323 std::make_shared<AnalyticsActions::Function>(
324 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
325 mDeviceConnection.createPatch(item);
326 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800327
Andy Hungea840382020-05-05 21:50:17 -0700328 // Called from BT service
329 mActions.addAction(
330 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
331 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
332 "." AMEDIAMETRICS_PROP_STATE,
333 "connected",
334 std::make_shared<AnalyticsActions::Function>(
335 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
336 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
337 }));
338
Joey Poomarin52989982020-03-05 17:40:49 +0800339 // Handle power usage
340 mActions.addAction(
341 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
342 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
343 std::make_shared<AnalyticsActions::Function>(
344 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
345 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
346 }));
347
348 mActions.addAction(
349 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
350 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
351 std::make_shared<AnalyticsActions::Function>(
352 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
353 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
354 }));
355
356 mActions.addAction(
357 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
358 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
359 std::make_shared<AnalyticsActions::Function>(
360 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
361 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
362 mAudioPowerUsage.checkMode(item);
363 }));
364
365 mActions.addAction(
366 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
367 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
368 std::make_shared<AnalyticsActions::Function>(
369 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
370 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
371 mAudioPowerUsage.checkVoiceVolume(item);
372 }));
373
374 mActions.addAction(
375 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
376 std::string("createAudioPatch"),
377 std::make_shared<AnalyticsActions::Function>(
378 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
379 mAudioPowerUsage.checkCreatePatch(item);
380 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800381}
382
383AudioAnalytics::~AudioAnalytics()
384{
385 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700386 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800387}
388
389status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800390 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800391{
Andy Hungea186fa2020-01-09 18:13:15 -0800392 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800393 status_t status = mAnalyticsState->submit(item, isTrusted);
394 if (status != NO_ERROR) return status; // may not be permitted.
395
396 // Only if the item was successfully submitted (permission)
397 // do we check triggered actions.
398 checkActions(item);
399 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800400}
401
Andy Hung709b91e2020-04-04 14:23:36 -0700402std::pair<std::string, int32_t> AudioAnalytics::dump(
403 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800404{
405 std::stringstream ss;
406 int32_t ll = lines;
407
408 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700409 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700410 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800411 ll -= l;
412 }
413 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800414 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800415 --ll;
416 }
417 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700418 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700419 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800420 ll -= l;
421 }
Joey Poomarin52989982020-03-05 17:40:49 +0800422
423 if (ll > 0 && prefix == nullptr) {
424 auto [s, l] = mAudioPowerUsage.dump(ll);
425 ss << s;
426 ll -= l;
427 }
Andy Hunga629bd12020-06-05 16:03:53 -0700428
Andy Hung06f3aba2019-12-03 16:36:42 -0800429 return { ss.str(), lines - ll };
430}
431
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800432void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
433{
434 auto actions = mActions.getActionsForItem(item); // internally locked.
435 // Execute actions with no lock held.
436 for (const auto& action : actions) {
437 (*action)(item);
438 }
439}
440
Andy Hungea186fa2020-01-09 18:13:15 -0800441// HELPER METHODS
442
443std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
444{
445 int32_t threadId_int32{};
446 if (mAnalyticsState->timeMachine().get(
447 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
448 return {};
449 }
450 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
451}
452
Andy Hungce9b6632020-04-28 20:15:17 -0700453// DeviceUse helper class.
454void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700455 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700456 const std::string& key = item->getKey();
457 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700458 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
459 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
460 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700461 - 1);
462 // deliver statistics
463 int64_t deviceTimeNs = 0;
464 mAudioAnalytics.mAnalyticsState->timeMachine().get(
465 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
466 std::string encoding;
467 mAudioAnalytics.mAnalyticsState->timeMachine().get(
468 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
469 int32_t frameCount = 0;
470 mAudioAnalytics.mAnalyticsState->timeMachine().get(
471 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700472 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700473 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700474 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700475 int32_t intervalCount = 0;
476 mAudioAnalytics.mAnalyticsState->timeMachine().get(
477 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700478 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700479 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700480 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700481 int32_t sampleRate = 0;
482 mAudioAnalytics.mAnalyticsState->timeMachine().get(
483 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700484 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700485 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700486 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700487
Andy Hungea840382020-05-05 21:50:17 -0700488 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700489 // Accumulate the bit flags for input and output devices.
490 std::stringstream oss;
491 long_enum_type_t outputDeviceBits{};
492 { // compute outputDevices
493 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700494 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700495 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
496 oss << device;
497 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700498 }
499 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700500 const std::string outputDevices = oss.str();
501
502 std::stringstream iss;
503 long_enum_type_t inputDeviceBits{};
504 { // compute inputDevices
505 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
506 for (const auto& [device, addr] : devaddrvec) {
507 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
508 iss << device;
509 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
510 }
511 }
512 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700513
514 // Get connected device name if from bluetooth.
515 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700516
517 std::string inputDeviceNames; // not filled currently.
518 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700519 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
520 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700521 outputDeviceNames = SUPPRESSED;
522#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700523 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700524 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700525 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700526 stringutils::replace(outputDeviceNames, "|", '?');
527 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
528 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
529 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700530#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700531 }
532
Andy Hungea840382020-05-05 21:50:17 -0700533 switch (itemType) {
534 case RECORD: {
535 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700536 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
537 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700538
Andy Hungea840382020-05-05 21:50:17 -0700539 std::string packageName;
540 int64_t versionCode = 0;
541 int32_t uid = -1;
542 mAudioAnalytics.mAnalyticsState->timeMachine().get(
543 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
544 if (uid != -1) {
545 std::tie(packageName, versionCode) =
546 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
547 }
548
549 int32_t selectedDeviceId = 0;
550 mAudioAnalytics.mAnalyticsState->timeMachine().get(
551 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
552 std::string source;
553 mAudioAnalytics.mAnalyticsState->timeMachine().get(
554 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800555 // Android S
556 std::string logSessionId;
557 mAudioAnalytics.mAnalyticsState->timeMachine().get(
558 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700559
Andy Hung1ea842e2020-05-18 10:47:31 -0700560 const auto callerNameForStats =
561 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
562 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
563 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
564 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800565 // Android S
566 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700567
Andy Hunga629bd12020-06-05 16:03:53 -0700568 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700569 << " id:" << id
570 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700571 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700572 << " deviceTimeNs:" << deviceTimeNs
573 << " encoding:" << encoding << "(" << encodingForStats
574 << ") frameCount:" << frameCount
575 << " intervalCount:" << intervalCount
576 << " sampleRate:" << sampleRate
577 << " flags:" << flags << "(" << flagsForStats
578 << ") packageName:" << packageName
579 << " selectedDeviceId:" << selectedDeviceId
580 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800581 << ") source:" << source << "(" << sourceForStats
582 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
583 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700584 if (clientCalled // only log if client app called AudioRecord.
585 && mAudioAnalytics.mDeliverStatistics) {
586 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
587 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700588 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700589 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700590 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700591 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700592 , frameCount
593 , intervalCount
594 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700595 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700596
597 , packageName.c_str()
598 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700599 , ENUM_EXTRACT(callerNameForStats)
600 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800601 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700602 );
Andy Hunga629bd12020-06-05 16:03:53 -0700603 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700604 mAudioAnalytics.mStatsdLog->log(
605 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700606 }
Andy Hungea840382020-05-05 21:50:17 -0700607 } break;
608 case THREAD: {
609 std::string type;
610 mAudioAnalytics.mAnalyticsState->timeMachine().get(
611 key, AMEDIAMETRICS_PROP_TYPE, &type);
612 int32_t underrun = 0; // zero for record types
613 mAudioAnalytics.mAnalyticsState->timeMachine().get(
614 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700615
616 const bool isInput = types::isInputThreadType(type);
617 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
618 const auto flagsForStats =
619 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
620 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
621 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
622
Andy Hunga629bd12020-06-05 16:03:53 -0700623 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700624 << " id:" << id
625 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
626 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700627 << ") inputDeviceNames:" << inputDeviceNames
628 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700629 << " deviceTimeNs:" << deviceTimeNs
630 << " encoding:" << encoding << "(" << encodingForStats
631 << ") frameCount:" << frameCount
632 << " intervalCount:" << intervalCount
633 << " sampleRate:" << sampleRate
634 << " underrun:" << underrun
635 << " flags:" << flags << "(" << flagsForStats
636 << ") type:" << type << "(" << typeForStats
637 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700638 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700639 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
640 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
641 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
642 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700643 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700644 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700645 , frameCount
646 , intervalCount
647 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700648 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700649 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700650 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700651 );
Andy Hunga629bd12020-06-05 16:03:53 -0700652 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700653 mAudioAnalytics.mStatsdLog->log(
654 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700655 }
Andy Hungea840382020-05-05 21:50:17 -0700656 } break;
657 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700658 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700659 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
660 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
661
Andy Hungce9b6632020-04-28 20:15:17 -0700662 std::string contentType;
663 mAudioAnalytics.mAnalyticsState->timeMachine().get(
664 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
665 double deviceLatencyMs = 0.;
666 mAudioAnalytics.mAnalyticsState->timeMachine().get(
667 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
668 double deviceStartupMs = 0.;
669 mAudioAnalytics.mAnalyticsState->timeMachine().get(
670 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
671 double deviceVolume = 0.;
672 mAudioAnalytics.mAnalyticsState->timeMachine().get(
673 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
674 std::string packageName;
675 int64_t versionCode = 0;
676 int32_t uid = -1;
677 mAudioAnalytics.mAnalyticsState->timeMachine().get(
678 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
679 if (uid != -1) {
680 std::tie(packageName, versionCode) =
681 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
682 }
683 double playbackPitch = 0.;
684 mAudioAnalytics.mAnalyticsState->timeMachine().get(
685 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
686 double playbackSpeed = 0.;
687 mAudioAnalytics.mAnalyticsState->timeMachine().get(
688 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
689 int32_t selectedDeviceId = 0;
690 mAudioAnalytics.mAnalyticsState->timeMachine().get(
691 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700692 std::string streamType;
693 mAudioAnalytics.mAnalyticsState->timeMachine().get(
694 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700695 std::string traits;
696 mAudioAnalytics.mAnalyticsState->timeMachine().get(
697 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700698 int32_t underrun = 0;
699 mAudioAnalytics.mAnalyticsState->timeMachine().get(
700 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700701 std::string usage;
702 mAudioAnalytics.mAnalyticsState->timeMachine().get(
703 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800704 // Android S
705 std::string logSessionId;
706 mAudioAnalytics.mAnalyticsState->timeMachine().get(
707 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700708
Andy Hung1ea842e2020-05-18 10:47:31 -0700709 const auto callerNameForStats =
710 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
711 const auto contentTypeForStats =
712 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
713 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
714 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
715 const auto streamTypeForStats =
716 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700717 const auto traitsForStats =
718 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700719 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800720 // Android S
721 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700722
Andy Hunga629bd12020-06-05 16:03:53 -0700723 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700724 << " id:" << id
725 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700726 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700727 << " deviceTimeNs:" << deviceTimeNs
728 << " encoding:" << encoding << "(" << encodingForStats
729 << ") frameCount:" << frameCount
730 << " intervalCount:" << intervalCount
731 << " sampleRate:" << sampleRate
732 << " underrun:" << underrun
733 << " flags:" << flags << "(" << flagsForStats
734 << ") callerName:" << callerName << "(" << callerNameForStats
735 << ") contentType:" << contentType << "(" << contentTypeForStats
736 << ") deviceLatencyMs:" << deviceLatencyMs
737 << " deviceStartupMs:" << deviceStartupMs
738 << " deviceVolume:" << deviceVolume
739 << " packageName:" << packageName
740 << " playbackPitch:" << playbackPitch
741 << " playbackSpeed:" << playbackSpeed
742 << " selectedDeviceId:" << selectedDeviceId
743 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700744 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700745 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800746 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700747 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700748 if (clientCalled // only log if client app called AudioTracks
749 && mAudioAnalytics.mDeliverStatistics) {
750 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
751 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700752 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700753 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700754 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700755 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700756 , frameCount
757 , intervalCount
758 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700759 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700760 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700761 , packageName.c_str()
762 , (float)deviceLatencyMs
763 , (float)deviceStartupMs
764 , (float)deviceVolume
765 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700766 , ENUM_EXTRACT(streamTypeForStats)
767 , ENUM_EXTRACT(usageForStats)
768 , ENUM_EXTRACT(contentTypeForStats)
769 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700770 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800771 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700772 );
Andy Hunga629bd12020-06-05 16:03:53 -0700773 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700774 mAudioAnalytics.mStatsdLog->log(
775 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -0700776 }
Andy Hungea840382020-05-05 21:50:17 -0700777 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700778 }
779
780 // Report this as needed.
781 if (isBluetooth) {
782 // report this for Bluetooth
783 }
784}
785
786// DeviceConnection helper class.
787void AudioAnalytics::DeviceConnection::a2dpConnected(
788 const std::shared_ptr<const android::mediametrics::Item> &item) {
789 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700790 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700791 {
792 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700793 mA2dpConnectionServiceNs = atNs;
794 ++mA2dpConnectionServices;
795
796 if (mA2dpConnectionRequestNs == 0) {
797 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
798 }
799 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700800 }
801 std::string name;
802 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700803 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
804 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700805}
806
807void AudioAnalytics::DeviceConnection::createPatch(
808 const std::shared_ptr<const android::mediametrics::Item> &item) {
809 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700810 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700811 const std::string& key = item->getKey();
812 std::string outputDevices;
813 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700814 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700815 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700816 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700817 if (mA2dpConnectionRequestNs == 0) {
818 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700819 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700820 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700821 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700822 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700823
Andy Hungea840382020-05-05 21:50:17 -0700824 mA2dpConnectionRequestNs = 0;
825 mA2dpConnectionServiceNs = 0;
826 ++mA2dpConnectionSuccesses;
827
Andy Hungc14ee142021-03-10 16:39:02 -0800828 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -0700829
830 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
831 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
832
Andy Hunga629bd12020-06-05 16:03:53 -0700833 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700834 << " A2DP SUCCESS"
835 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700836 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700837 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700838 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700839 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700840
841 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
842 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700843 , ENUM_EXTRACT(inputDeviceBits)
844 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700845 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700846 , types::DEVICE_CONNECTION_RESULT_SUCCESS
847 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700848 , /* connection_count */ 1
849 );
Andy Hunga629bd12020-06-05 16:03:53 -0700850 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700851 mAudioAnalytics.mStatsdLog->log(
852 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700853 }
Andy Hungce9b6632020-04-28 20:15:17 -0700854 }
855}
856
Andy Hungea840382020-05-05 21:50:17 -0700857// Called through AudioManager when the BT service wants to enable
858void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
859 const std::shared_ptr<const android::mediametrics::Item> &item) {
860 const int64_t atNs = item->getTimestamp();
861 const std::string& key = item->getKey();
862 std::string state;
863 item->get(AMEDIAMETRICS_PROP_STATE, &state);
864 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700865
866 std::string name;
867 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700868 {
869 std::lock_guard l(mLock);
870 mA2dpConnectionRequestNs = atNs;
871 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700872 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700873 }
Andy Hunga629bd12020-06-05 16:03:53 -0700874 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
875 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700876 // TODO: attempt to cancel a timed event, rather than let it expire.
877 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
878}
879
Andy Hungce9b6632020-04-28 20:15:17 -0700880void AudioAnalytics::DeviceConnection::expire() {
881 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700882 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700883
Andy Hung1ea842e2020-05-18 10:47:31 -0700884 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700885 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
886 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
887
Andy Hungea840382020-05-05 21:50:17 -0700888 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700889 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700890
Andy Hunga629bd12020-06-05 16:03:53 -0700891 LOG(LOG_LEVEL) << "A2DP CANCEL"
892 << " outputDevices:" << outputDeviceBits
893 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700894 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700895 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
896 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700897 , ENUM_EXTRACT(inputDeviceBits)
898 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700899 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700900 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700901 , /* connection_time_ms */ 0.f
902 , /* connection_count */ 1
903 );
Andy Hunga629bd12020-06-05 16:03:53 -0700904 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700905 mAudioAnalytics.mStatsdLog->log(
906 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700907 }
Andy Hungea840382020-05-05 21:50:17 -0700908 return;
909 }
910
911 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
912 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700913 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700914 mA2dpConnectionRequestNs = 0;
915 mA2dpConnectionServiceNs = 0;
916 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700917
Andy Hunga629bd12020-06-05 16:03:53 -0700918 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
919 << " outputDevices:" << outputDeviceBits
920 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700921 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700922 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
923 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700924 , ENUM_EXTRACT(inputDeviceBits)
925 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700926 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700927 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700928 , /* connection_time_ms */ 0.f
929 , /* connection_count */ 1
930 );
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_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700934 }
Andy Hungce9b6632020-04-28 20:15:17 -0700935}
936
jiabin515eb092020-11-18 17:55:52 -0800937void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
938 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
939 const std::string& key = item->getKey();
940
jiabin515eb092020-11-18 17:55:52 -0800941 std::string directionStr;
942 mAudioAnalytics.mAnalyticsState->timeMachine().get(
943 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
944 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
945
946 int32_t framesPerBurst = -1;
947 mAudioAnalytics.mAnalyticsState->timeMachine().get(
948 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
949
950 int32_t bufferSizeInFrames = -1;
951 mAudioAnalytics.mAnalyticsState->timeMachine().get(
952 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
953
954 int32_t bufferCapacityInFrames = -1;
955 mAudioAnalytics.mAnalyticsState->timeMachine().get(
956 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
957
958 int32_t channelCount = -1;
959 mAudioAnalytics.mAnalyticsState->timeMachine().get(
960 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabina2202852021-07-28 22:15:01 +0000961 if (channelCount == -1) {
962 // Try to get channel count from channel mask. From the legacy path,
963 // only channel mask are logged.
964 int32_t channelMask = 0;
965 mAudioAnalytics.mAnalyticsState->timeMachine().get(
966 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
967 if (channelMask != 0) {
968 switch (direction) {
969 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -0800970 channelCount = (int32_t)audio_channel_count_from_out_mask(channelMask);
jiabina2202852021-07-28 22:15:01 +0000971 break;
972 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
Andy Hungefc56a72022-02-25 13:28:13 -0800973 channelCount = (int32_t)audio_channel_count_from_in_mask(channelMask);
jiabina2202852021-07-28 22:15:01 +0000974 break;
975 default:
976 ALOGW("Invalid direction %d", direction);
977 }
978 }
979 }
jiabin515eb092020-11-18 17:55:52 -0800980
981 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +0000982 mAudioAnalytics.mAnalyticsState->timeMachine().get(
983 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -0800984
985 std::string perfModeRequestedStr;
986 mAudioAnalytics.mAnalyticsState->timeMachine().get(
987 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
988 const auto perfModeRequested =
989 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
990
jiabin97247ea2021-04-07 00:33:38 +0000991 std::string perfModeActualStr;
992 mAudioAnalytics.mAnalyticsState->timeMachine().get(
993 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
994 const auto perfModeActual =
995 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -0800996
jiabinc8da9032021-04-28 20:42:36 +0000997 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -0800998 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +0000999 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1000 const auto sharingModeActual =
1001 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001002
1003 int32_t xrunCount = -1;
1004 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1005 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1006
jiabin92c9a522021-02-12 22:37:42 +00001007 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001008 // TODO: only routed device id is logged, but no device type
1009
jiabin97247ea2021-04-07 00:33:38 +00001010 std::string formatAppStr;
1011 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001012 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001013 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001014
1015 std::string formatDeviceStr;
1016 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1017 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1018 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1019
jiabin92c9a522021-02-12 22:37:42 +00001020 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001021 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1022 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001023
jiabinc4c331c2021-03-23 17:11:01 +00001024 int32_t sampleRate = 0;
1025 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1026 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1027
1028 std::string contentTypeStr;
1029 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1030 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1031 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1032
jiabinc8da9032021-04-28 20:42:36 +00001033 std::string sharingModeRequestedStr;
1034 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1035 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1036 const auto sharingModeRequested =
1037 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1038
jiabin515eb092020-11-18 17:55:52 -08001039 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001040 << " path:" << path
1041 << " direction:" << direction << "(" << directionStr << ")"
1042 << " frames_per_burst:" << framesPerBurst
1043 << " buffer_size:" << bufferSizeInFrames
1044 << " buffer_capacity:" << bufferCapacityInFrames
1045 << " channel_count:" << channelCount
1046 << " total_frames_transferred:" << totalFramesTransferred
1047 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001048 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001049 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001050 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001051 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001052 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001053 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001054 << " log_session_id: " << logSessionId
1055 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001056 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1057 << " sharing_requested:" << sharingModeRequested
1058 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001059
jiabin92c9a522021-02-12 22:37:42 +00001060 if (mAudioAnalytics.mDeliverStatistics) {
1061 android::util::BytesField bf_serialized(
1062 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1063 const auto result = sendToStatsd(
1064 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001065 , path
1066 , direction
1067 , framesPerBurst
1068 , bufferSizeInFrames
1069 , bufferCapacityInFrames
1070 , channelCount
1071 , totalFramesTransferred
1072 , perfModeRequested
1073 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001074 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001075 , xrunCount
1076 , bf_serialized
1077 , formatApp
1078 , formatDevice
1079 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001080 , sampleRate
1081 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001082 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001083 );
1084 std::stringstream ss;
1085 ss << "result:" << result;
1086 const auto fieldsStr = printFields(AAudioStreamFields,
1087 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001088 , path
1089 , direction
1090 , framesPerBurst
1091 , bufferSizeInFrames
1092 , bufferCapacityInFrames
1093 , channelCount
1094 , totalFramesTransferred
1095 , perfModeRequested
1096 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001097 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001098 , xrunCount
1099 , serializedDeviceTypes.c_str()
1100 , formatApp
1101 , formatDevice
1102 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001103 , sampleRate
1104 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001105 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001106 );
1107 ss << " " << fieldsStr;
1108 std::string str = ss.str();
1109 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001110 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001111 }
jiabin515eb092020-11-18 17:55:52 -08001112}
1113
Andy Hung3ab1b322020-05-18 10:47:31 -07001114} // namespace android::mediametrics