blob: 270fe2f607fc10ef3d45c1ae2a895240140cb2b6 [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
jiabinfbf20302021-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"
Andy Hungc9b6f8b2021-07-08 10:17:55 -070032#include "ValidateId.h"
Andy Hung1ea842e2020-05-18 10:47:31 -070033
34#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
35
Andy Hunga629bd12020-06-05 16:03:53 -070036namespace android::mediametrics {
Andy Hung1ea842e2020-05-18 10:47:31 -070037
Andy Hunga629bd12020-06-05 16:03:53 -070038// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
Andy Hunga0a5ad22020-06-12 09:30:34 -070039#define STATSD_ENABLE
Andy Hung1ea842e2020-05-18 10:47:31 -070040
Andy Hunga629bd12020-06-05 16:03:53 -070041#ifdef STATSD_ENABLE
42#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
Andy Hung1ea842e2020-05-18 10:47:31 -070043#else
Andy Hunga629bd12020-06-05 16:03:53 -070044#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
Andy Hung1ea842e2020-05-18 10:47:31 -070045#endif
46
Andy Hunga629bd12020-06-05 16:03:53 -070047// Maximum length of a device name.
Andy Hung3deef2b2020-07-17 12:58:54 -070048// static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
Andy Hung06f3aba2019-12-03 16:36:42 -080049
Andy Hunga629bd12020-06-05 16:03:53 -070050// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
51static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
52
53// derive types based on integer or strings.
54using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
55using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
56
57// Convert std::string to char *
58template <typename T>
59auto ENUM_EXTRACT(const T& x) {
60 if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
61 return x.c_str();
62 } else {
63 return x;
64 }
65}
66
67static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
68
Andy Hungb18f5062020-06-18 23:10:08 -070069static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
70
Andy Hung3deef2b2020-07-17 12:58:54 -070071static constexpr const char * SUPPRESSED = "SUPPRESSED";
72
Andy Hunga629bd12020-06-05 16:03:53 -070073/*
74 * For logging purposes, we list all of the MediaMetrics atom fields,
75 * which can then be associated with consecutive arguments to the statsd write.
76 */
77
78static constexpr const char * const AudioRecordDeviceUsageFields[] = {
79 "mediametrics_audiorecorddeviceusage_reported", // proto number
80 "devices",
81 "device_names",
82 "device_time_nanos",
83 "encoding",
84 "frame_count",
85 "interval_count",
86 "sample_rate",
87 "flags",
88 "package_name",
89 "selected_device_id",
90 "caller",
91 "source",
Andy Hungcbcfaa22021-02-23 13:54:49 -080092 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -070093};
94
95static constexpr const char * const AudioThreadDeviceUsageFields[] = {
96 "mediametrics_audiothreaddeviceusage_reported",
97 "devices",
98 "device_names",
99 "device_time_nanos",
100 "encoding",
101 "frame_count",
102 "interval_count",
103 "sample_rate",
104 "flags",
105 "xruns",
106 "type",
107};
108
109static constexpr const char * const AudioTrackDeviceUsageFields[] = {
110 "mediametrics_audiotrackdeviceusage_reported",
111 "devices",
112 "device_names",
113 "device_time_nanos",
114 "encoding",
115 "frame_count",
116 "interval_count",
117 "sample_rate",
118 "flags",
119 "xruns",
120 "package_name",
121 "device_latency_millis",
122 "device_startup_millis",
123 "device_volume",
124 "selected_device_id",
125 "stream_type",
126 "usage",
127 "content_type",
128 "caller",
129 "traits",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800130 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700131};
132
133static constexpr const char * const AudioDeviceConnectionFields[] = {
134 "mediametrics_audiodeviceconnection_reported",
135 "input_devices",
136 "output_devices",
137 "device_names",
138 "result",
139 "time_to_connect_millis",
140 "connection_count",
141};
142
jiabin92c9a522021-02-12 22:37:42 +0000143static constexpr const char * const AAudioStreamFields[] {
144 "mediametrics_aaudiostream_reported",
jiabin92c9a522021-02-12 22:37:42 +0000145 "path",
146 "direction",
147 "frames_per_burst",
148 "buffer_size",
149 "buffer_capacity",
150 "channel_count",
151 "total_frames_transferred",
152 "perf_mode_requested",
153 "perf_mode_actual",
154 "sharing",
155 "xrun_count",
156 "device_type",
157 "format_app",
158 "format_device",
159 "log_session_id",
jiabinc4c331c2021-03-23 17:11:01 +0000160 "sample_rate",
161 "content_type",
jiabinc8da9032021-04-28 20:42:36 +0000162 "sharing_requested",
jiabin92c9a522021-02-12 22:37:42 +0000163};
164
165/**
166 * printFields is a helper method that prints the fields and corresponding values
167 * in a human readable style.
168 */
169template <size_t N, typename ...Types>
170std::string printFields(const char * const (& fields)[N], Types ... args)
171{
172 std::stringstream ss;
173 ss << " { ";
174 stringutils::fieldPrint(ss, fields, args...);
175 ss << "}";
176 return ss.str();
177}
178
179/**
180 * sendToStatsd is a helper method that sends the arguments to statsd
181 */
182template <typename ...Types>
183int sendToStatsd(Types ... args)
184{
185 int result = 0;
186
187#ifdef STATSD_ENABLE
188 result = android::util::stats_write(args...);
189#endif
190 return result;
191}
jiabin515eb092020-11-18 17:55:52 -0800192
Andy Hunga629bd12020-06-05 16:03:53 -0700193/**
194 * sendToStatsd is a helper method that sends the arguments to statsd
195 * and returns a pair { result, summary_string }.
196 */
197template <size_t N, typename ...Types>
198std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
199{
200 int result = 0;
201 std::stringstream ss;
202
203#ifdef STATSD_ENABLE
204 result = android::util::stats_write(args...);
205 ss << "result:" << result;
206#endif
207 ss << " { ";
208 stringutils::fieldPrint(ss, fields, args...);
209 ss << "}";
210 return { result, ss.str() };
211}
Andy Hung06f3aba2019-12-03 16:36:42 -0800212
Andy Hung5be90c82021-03-30 14:30:20 -0700213AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700214 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700215 , mStatsdLog(statsdLog)
216 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800217{
Andy Hunga629bd12020-06-05 16:03:53 -0700218 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800219 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800220
221 // Add action to save AnalyticsState if audioserver is restarted.
222 // This triggers on an item of "audio.flinger"
223 // with a property "event" set to "AudioFlinger" (the constructor).
224 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800225 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
226 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800227 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800228 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
229 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800230 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
231 *mAnalyticsState.get()));
232 // Note: get returns shared_ptr temp, whose lifetime is extended
233 // to end of full expression.
234 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800235 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700236
237 // Set up a timer to expire the previous audio state to save space.
238 // Use the transaction log size as a cookie to see if it is the
239 // same as before. A benign race is possible where a state is cleared early.
240 const size_t size = mPreviousAnalyticsState->transactionLog().size();
241 mTimedAction.postIn(
242 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
243 if (mPreviousAnalyticsState->transactionLog().size() == size) {
244 ALOGD("expiring previous audio state after %d seconds.",
245 PREVIOUS_STATE_EXPIRE_SEC);
246 mPreviousAnalyticsState->clear(); // removes data from the state.
247 }
248 });
Andy Hungea186fa2020-01-09 18:13:15 -0800249 }));
250
jiabin97247ea2021-04-07 00:33:38 +0000251 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800252 mActions.addAction(
253 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
254 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
255 std::make_shared<AnalyticsActions::Function>(
256 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
257 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
258 }));
259
jiabin97247ea2021-04-07 00:33:38 +0000260 // Handle legacy aaudio capture stream statistics
261 mActions.addAction(
262 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
263 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
264 std::make_shared<AnalyticsActions::Function>(
265 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
266 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
267 }));
268
jiabin515eb092020-11-18 17:55:52 -0800269 // Handle mmap aaudio stream statistics
270 mActions.addAction(
271 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
272 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
273 std::make_shared<AnalyticsActions::Function>(
274 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
275 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
276 }));
277
Andy Hungea840382020-05-05 21:50:17 -0700278 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800279 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700280 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
281 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800282 std::make_shared<AnalyticsActions::Function>(
283 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700284 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800285 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700286
287 // Handle device use thread statistics
288 mActions.addAction(
289 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
290 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
291 std::make_shared<AnalyticsActions::Function>(
292 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700293 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700294 }));
295
296 // Handle device use track statistics
297 mActions.addAction(
298 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
299 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
300 std::make_shared<AnalyticsActions::Function>(
301 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700302 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700303 }));
304
Andy Hungea840382020-05-05 21:50:17 -0700305
306 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700307
308 // We track connections (not disconnections) for the time to connect.
309 // TODO: consider BT requests in their A2dp service
310 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
311 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
312 // AudioDeviceBroker.postA2dpActiveDeviceChange
313 mActions.addAction(
314 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700315 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700316 std::make_shared<AnalyticsActions::Function>(
317 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
318 mDeviceConnection.a2dpConnected(item);
319 }));
320 // If audio is active, we expect to see a createAudioPatch after the device is connected.
321 mActions.addAction(
322 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
323 std::string("createAudioPatch"),
324 std::make_shared<AnalyticsActions::Function>(
325 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
326 mDeviceConnection.createPatch(item);
327 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800328
Andy Hungea840382020-05-05 21:50:17 -0700329 // Called from BT service
330 mActions.addAction(
331 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
332 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
333 "." AMEDIAMETRICS_PROP_STATE,
334 "connected",
335 std::make_shared<AnalyticsActions::Function>(
336 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
337 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
338 }));
339
Joey Poomarin52989982020-03-05 17:40:49 +0800340 // Handle power usage
341 mActions.addAction(
342 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
343 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
344 std::make_shared<AnalyticsActions::Function>(
345 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
346 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
347 }));
348
349 mActions.addAction(
350 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
351 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
352 std::make_shared<AnalyticsActions::Function>(
353 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
354 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
355 }));
356
357 mActions.addAction(
358 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
359 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
360 std::make_shared<AnalyticsActions::Function>(
361 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
362 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
363 mAudioPowerUsage.checkMode(item);
364 }));
365
366 mActions.addAction(
367 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
368 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
369 std::make_shared<AnalyticsActions::Function>(
370 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
371 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
372 mAudioPowerUsage.checkVoiceVolume(item);
373 }));
374
375 mActions.addAction(
376 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
377 std::string("createAudioPatch"),
378 std::make_shared<AnalyticsActions::Function>(
379 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
380 mAudioPowerUsage.checkCreatePatch(item);
381 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800382}
383
384AudioAnalytics::~AudioAnalytics()
385{
386 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700387 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800388}
389
390status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800391 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800392{
Andy Hungea186fa2020-01-09 18:13:15 -0800393 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800394 status_t status = mAnalyticsState->submit(item, isTrusted);
395 if (status != NO_ERROR) return status; // may not be permitted.
396
397 // Only if the item was successfully submitted (permission)
398 // do we check triggered actions.
399 checkActions(item);
400 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800401}
402
Andy Hung709b91e2020-04-04 14:23:36 -0700403std::pair<std::string, int32_t> AudioAnalytics::dump(
404 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800405{
406 std::stringstream ss;
407 int32_t ll = lines;
408
409 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700410 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700411 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800412 ll -= l;
413 }
414 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800415 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800416 --ll;
417 }
418 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700419 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700420 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800421 ll -= l;
422 }
Joey Poomarin52989982020-03-05 17:40:49 +0800423
424 if (ll > 0 && prefix == nullptr) {
425 auto [s, l] = mAudioPowerUsage.dump(ll);
426 ss << s;
427 ll -= l;
428 }
Andy Hunga629bd12020-06-05 16:03:53 -0700429
Andy Hung06f3aba2019-12-03 16:36:42 -0800430 return { ss.str(), lines - ll };
431}
432
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800433void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
434{
435 auto actions = mActions.getActionsForItem(item); // internally locked.
436 // Execute actions with no lock held.
437 for (const auto& action : actions) {
438 (*action)(item);
439 }
440}
441
Andy Hungea186fa2020-01-09 18:13:15 -0800442// HELPER METHODS
443
444std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
445{
446 int32_t threadId_int32{};
447 if (mAnalyticsState->timeMachine().get(
448 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
449 return {};
450 }
451 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
452}
453
Andy Hungce9b6632020-04-28 20:15:17 -0700454// DeviceUse helper class.
455void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700456 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700457 const std::string& key = item->getKey();
458 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700459 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
460 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
461 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700462 - 1);
463 // deliver statistics
464 int64_t deviceTimeNs = 0;
465 mAudioAnalytics.mAnalyticsState->timeMachine().get(
466 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
467 std::string encoding;
468 mAudioAnalytics.mAnalyticsState->timeMachine().get(
469 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
470 int32_t frameCount = 0;
471 mAudioAnalytics.mAnalyticsState->timeMachine().get(
472 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700473 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700474 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700475 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700476 int32_t intervalCount = 0;
477 mAudioAnalytics.mAnalyticsState->timeMachine().get(
478 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700479 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700480 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700481 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700482 int32_t sampleRate = 0;
483 mAudioAnalytics.mAnalyticsState->timeMachine().get(
484 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700485 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700486 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700487 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700488
Andy Hungea840382020-05-05 21:50:17 -0700489 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700490 // Accumulate the bit flags for input and output devices.
491 std::stringstream oss;
492 long_enum_type_t outputDeviceBits{};
493 { // compute outputDevices
494 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700495 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700496 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
497 oss << device;
498 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700499 }
500 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700501 const std::string outputDevices = oss.str();
502
503 std::stringstream iss;
504 long_enum_type_t inputDeviceBits{};
505 { // compute inputDevices
506 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
507 for (const auto& [device, addr] : devaddrvec) {
508 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
509 iss << device;
510 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
511 }
512 }
513 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700514
515 // Get connected device name if from bluetooth.
516 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700517
518 std::string inputDeviceNames; // not filled currently.
519 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700520 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
521 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700522 outputDeviceNames = SUPPRESSED;
523#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700524 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700525 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700526 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700527 stringutils::replace(outputDeviceNames, "|", '?');
528 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
529 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
530 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700531#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700532 }
533
Andy Hungea840382020-05-05 21:50:17 -0700534 switch (itemType) {
535 case RECORD: {
536 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700537 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
538 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700539
Andy Hungea840382020-05-05 21:50:17 -0700540 std::string packageName;
541 int64_t versionCode = 0;
542 int32_t uid = -1;
543 mAudioAnalytics.mAnalyticsState->timeMachine().get(
544 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
545 if (uid != -1) {
546 std::tie(packageName, versionCode) =
547 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
548 }
549
550 int32_t selectedDeviceId = 0;
551 mAudioAnalytics.mAnalyticsState->timeMachine().get(
552 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
553 std::string source;
554 mAudioAnalytics.mAnalyticsState->timeMachine().get(
555 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800556 // Android S
557 std::string logSessionId;
558 mAudioAnalytics.mAnalyticsState->timeMachine().get(
559 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700560
Andy Hung1ea842e2020-05-18 10:47:31 -0700561 const auto callerNameForStats =
562 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
563 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
564 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
565 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800566 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700567 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700568
Andy Hunga629bd12020-06-05 16:03:53 -0700569 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700570 << " id:" << id
571 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700572 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700573 << " deviceTimeNs:" << deviceTimeNs
574 << " encoding:" << encoding << "(" << encodingForStats
575 << ") frameCount:" << frameCount
576 << " intervalCount:" << intervalCount
577 << " sampleRate:" << sampleRate
578 << " flags:" << flags << "(" << flagsForStats
579 << ") packageName:" << packageName
580 << " selectedDeviceId:" << selectedDeviceId
581 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800582 << ") source:" << source << "(" << sourceForStats
583 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
584 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700585 if (clientCalled // only log if client app called AudioRecord.
586 && mAudioAnalytics.mDeliverStatistics) {
587 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
588 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700589 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700590 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700591 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700592 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700593 , frameCount
594 , intervalCount
595 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700596 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700597
598 , packageName.c_str()
599 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700600 , ENUM_EXTRACT(callerNameForStats)
601 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800602 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700603 );
Andy Hunga629bd12020-06-05 16:03:53 -0700604 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700605 mAudioAnalytics.mStatsdLog->log(
606 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700607 }
Andy Hungea840382020-05-05 21:50:17 -0700608 } break;
609 case THREAD: {
610 std::string type;
611 mAudioAnalytics.mAnalyticsState->timeMachine().get(
612 key, AMEDIAMETRICS_PROP_TYPE, &type);
613 int32_t underrun = 0; // zero for record types
614 mAudioAnalytics.mAnalyticsState->timeMachine().get(
615 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700616
617 const bool isInput = types::isInputThreadType(type);
618 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
619 const auto flagsForStats =
620 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
621 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
622 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
623
Andy Hunga629bd12020-06-05 16:03:53 -0700624 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700625 << " id:" << id
626 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
627 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700628 << ") inputDeviceNames:" << inputDeviceNames
629 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700630 << " deviceTimeNs:" << deviceTimeNs
631 << " encoding:" << encoding << "(" << encodingForStats
632 << ") frameCount:" << frameCount
633 << " intervalCount:" << intervalCount
634 << " sampleRate:" << sampleRate
635 << " underrun:" << underrun
636 << " flags:" << flags << "(" << flagsForStats
637 << ") type:" << type << "(" << typeForStats
638 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700639 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700640 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
641 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
642 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
643 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700644 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700645 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700646 , frameCount
647 , intervalCount
648 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700649 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700650 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700651 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700652 );
Andy Hunga629bd12020-06-05 16:03:53 -0700653 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700654 mAudioAnalytics.mStatsdLog->log(
655 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700656 }
Andy Hungea840382020-05-05 21:50:17 -0700657 } break;
658 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700659 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700660 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
661 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
662
Andy Hungce9b6632020-04-28 20:15:17 -0700663 std::string contentType;
664 mAudioAnalytics.mAnalyticsState->timeMachine().get(
665 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
666 double deviceLatencyMs = 0.;
667 mAudioAnalytics.mAnalyticsState->timeMachine().get(
668 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
669 double deviceStartupMs = 0.;
670 mAudioAnalytics.mAnalyticsState->timeMachine().get(
671 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
672 double deviceVolume = 0.;
673 mAudioAnalytics.mAnalyticsState->timeMachine().get(
674 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
675 std::string packageName;
676 int64_t versionCode = 0;
677 int32_t uid = -1;
678 mAudioAnalytics.mAnalyticsState->timeMachine().get(
679 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
680 if (uid != -1) {
681 std::tie(packageName, versionCode) =
682 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
683 }
684 double playbackPitch = 0.;
685 mAudioAnalytics.mAnalyticsState->timeMachine().get(
686 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
687 double playbackSpeed = 0.;
688 mAudioAnalytics.mAnalyticsState->timeMachine().get(
689 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
690 int32_t selectedDeviceId = 0;
691 mAudioAnalytics.mAnalyticsState->timeMachine().get(
692 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700693 std::string streamType;
694 mAudioAnalytics.mAnalyticsState->timeMachine().get(
695 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700696 std::string traits;
697 mAudioAnalytics.mAnalyticsState->timeMachine().get(
698 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700699 int32_t underrun = 0;
700 mAudioAnalytics.mAnalyticsState->timeMachine().get(
701 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700702 std::string usage;
703 mAudioAnalytics.mAnalyticsState->timeMachine().get(
704 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800705 // Android S
706 std::string logSessionId;
707 mAudioAnalytics.mAnalyticsState->timeMachine().get(
708 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700709
Andy Hung1ea842e2020-05-18 10:47:31 -0700710 const auto callerNameForStats =
711 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
712 const auto contentTypeForStats =
713 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
714 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
715 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
716 const auto streamTypeForStats =
717 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700718 const auto traitsForStats =
719 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700720 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800721 // Android S
Andy Hungc9b6f8b2021-07-08 10:17:55 -0700722 const auto logSessionIdForStats = ValidateId::get()->validateId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700723
Andy Hunga629bd12020-06-05 16:03:53 -0700724 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700725 << " id:" << id
726 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700727 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700728 << " deviceTimeNs:" << deviceTimeNs
729 << " encoding:" << encoding << "(" << encodingForStats
730 << ") frameCount:" << frameCount
731 << " intervalCount:" << intervalCount
732 << " sampleRate:" << sampleRate
733 << " underrun:" << underrun
734 << " flags:" << flags << "(" << flagsForStats
735 << ") callerName:" << callerName << "(" << callerNameForStats
736 << ") contentType:" << contentType << "(" << contentTypeForStats
737 << ") deviceLatencyMs:" << deviceLatencyMs
738 << " deviceStartupMs:" << deviceStartupMs
739 << " deviceVolume:" << deviceVolume
740 << " packageName:" << packageName
741 << " playbackPitch:" << playbackPitch
742 << " playbackSpeed:" << playbackSpeed
743 << " selectedDeviceId:" << selectedDeviceId
744 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700745 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700746 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800747 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700748 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700749 if (clientCalled // only log if client app called AudioTracks
750 && mAudioAnalytics.mDeliverStatistics) {
751 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
752 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700753 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700754 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700755 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700756 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700757 , frameCount
758 , intervalCount
759 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700760 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700761 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700762 , packageName.c_str()
763 , (float)deviceLatencyMs
764 , (float)deviceStartupMs
765 , (float)deviceVolume
766 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700767 , ENUM_EXTRACT(streamTypeForStats)
768 , ENUM_EXTRACT(usageForStats)
769 , ENUM_EXTRACT(contentTypeForStats)
770 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700771 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800772 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700773 );
Andy Hunga629bd12020-06-05 16:03:53 -0700774 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700775 mAudioAnalytics.mStatsdLog->log(
776 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -0700777 }
Andy Hungea840382020-05-05 21:50:17 -0700778 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700779 }
780
781 // Report this as needed.
782 if (isBluetooth) {
783 // report this for Bluetooth
784 }
785}
786
787// DeviceConnection helper class.
788void AudioAnalytics::DeviceConnection::a2dpConnected(
789 const std::shared_ptr<const android::mediametrics::Item> &item) {
790 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700791 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700792 {
793 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700794 mA2dpConnectionServiceNs = atNs;
795 ++mA2dpConnectionServices;
796
797 if (mA2dpConnectionRequestNs == 0) {
798 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
799 }
800 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700801 }
802 std::string name;
803 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700804 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
805 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700806}
807
808void AudioAnalytics::DeviceConnection::createPatch(
809 const std::shared_ptr<const android::mediametrics::Item> &item) {
810 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700811 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700812 const std::string& key = item->getKey();
813 std::string outputDevices;
814 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700815 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700816 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700817 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700818 if (mA2dpConnectionRequestNs == 0) {
819 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700820 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700821 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700822 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700823 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700824
Andy Hungea840382020-05-05 21:50:17 -0700825 mA2dpConnectionRequestNs = 0;
826 mA2dpConnectionServiceNs = 0;
827 ++mA2dpConnectionSuccesses;
828
Andy Hungc14ee142021-03-10 16:39:02 -0800829 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -0700830
831 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
832 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
833
Andy Hunga629bd12020-06-05 16:03:53 -0700834 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700835 << " A2DP SUCCESS"
836 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700837 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700838 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700839 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700840 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700841
842 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
843 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700844 , ENUM_EXTRACT(inputDeviceBits)
845 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700846 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700847 , types::DEVICE_CONNECTION_RESULT_SUCCESS
848 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700849 , /* connection_count */ 1
850 );
Andy Hunga629bd12020-06-05 16:03:53 -0700851 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700852 mAudioAnalytics.mStatsdLog->log(
853 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700854 }
Andy Hungce9b6632020-04-28 20:15:17 -0700855 }
856}
857
Andy Hungea840382020-05-05 21:50:17 -0700858// Called through AudioManager when the BT service wants to enable
859void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
860 const std::shared_ptr<const android::mediametrics::Item> &item) {
861 const int64_t atNs = item->getTimestamp();
862 const std::string& key = item->getKey();
863 std::string state;
864 item->get(AMEDIAMETRICS_PROP_STATE, &state);
865 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700866
867 std::string name;
868 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700869 {
870 std::lock_guard l(mLock);
871 mA2dpConnectionRequestNs = atNs;
872 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700873 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700874 }
Andy Hunga629bd12020-06-05 16:03:53 -0700875 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
876 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700877 // TODO: attempt to cancel a timed event, rather than let it expire.
878 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
879}
880
Andy Hungce9b6632020-04-28 20:15:17 -0700881void AudioAnalytics::DeviceConnection::expire() {
882 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700883 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700884
Andy Hung1ea842e2020-05-18 10:47:31 -0700885 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700886 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
887 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
888
Andy Hungea840382020-05-05 21:50:17 -0700889 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700890 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700891
Andy Hunga629bd12020-06-05 16:03:53 -0700892 LOG(LOG_LEVEL) << "A2DP CANCEL"
893 << " outputDevices:" << outputDeviceBits
894 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700895 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700896 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
897 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700898 , ENUM_EXTRACT(inputDeviceBits)
899 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700900 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700901 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700902 , /* connection_time_ms */ 0.f
903 , /* connection_count */ 1
904 );
Andy Hunga629bd12020-06-05 16:03:53 -0700905 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700906 mAudioAnalytics.mStatsdLog->log(
907 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700908 }
Andy Hungea840382020-05-05 21:50:17 -0700909 return;
910 }
911
912 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
913 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700914 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700915 mA2dpConnectionRequestNs = 0;
916 mA2dpConnectionServiceNs = 0;
917 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700918
Andy Hunga629bd12020-06-05 16:03:53 -0700919 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
920 << " outputDevices:" << outputDeviceBits
921 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700922 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700923 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
924 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700925 , ENUM_EXTRACT(inputDeviceBits)
926 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700927 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700928 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700929 , /* connection_time_ms */ 0.f
930 , /* connection_count */ 1
931 );
Andy Hunga629bd12020-06-05 16:03:53 -0700932 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700933 mAudioAnalytics.mStatsdLog->log(
934 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700935 }
Andy Hungce9b6632020-04-28 20:15:17 -0700936}
937
jiabin515eb092020-11-18 17:55:52 -0800938void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
939 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
940 const std::string& key = item->getKey();
941
jiabin515eb092020-11-18 17:55:52 -0800942 std::string directionStr;
943 mAudioAnalytics.mAnalyticsState->timeMachine().get(
944 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
945 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
946
947 int32_t framesPerBurst = -1;
948 mAudioAnalytics.mAnalyticsState->timeMachine().get(
949 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
950
951 int32_t bufferSizeInFrames = -1;
952 mAudioAnalytics.mAnalyticsState->timeMachine().get(
953 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
954
955 int32_t bufferCapacityInFrames = -1;
956 mAudioAnalytics.mAnalyticsState->timeMachine().get(
957 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
958
959 int32_t channelCount = -1;
960 mAudioAnalytics.mAnalyticsState->timeMachine().get(
961 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
jiabinfbf20302021-07-28 22:15:01 +0000962 if (channelCount == -1) {
963 // Try to get channel count from channel mask. From the legacy path,
964 // only channel mask are logged.
965 int32_t channelMask = 0;
966 mAudioAnalytics.mAnalyticsState->timeMachine().get(
967 key, AMEDIAMETRICS_PROP_CHANNELMASK, &channelMask);
968 if (channelMask != 0) {
969 switch (direction) {
970 case 1: // Output, keep sync with AudioTypes#getAAudioDirection()
971 channelCount = audio_channel_count_from_out_mask(channelMask);
972 break;
973 case 2: // Input, keep sync with AudioTypes#getAAudioDirection()
974 channelCount = audio_channel_count_from_in_mask(channelMask);
975 break;
976 default:
977 ALOGW("Invalid direction %d", direction);
978 }
979 }
980 }
jiabin515eb092020-11-18 17:55:52 -0800981
982 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +0000983 mAudioAnalytics.mAnalyticsState->timeMachine().get(
984 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -0800985
986 std::string perfModeRequestedStr;
987 mAudioAnalytics.mAnalyticsState->timeMachine().get(
988 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
989 const auto perfModeRequested =
990 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
991
jiabin97247ea2021-04-07 00:33:38 +0000992 std::string perfModeActualStr;
993 mAudioAnalytics.mAnalyticsState->timeMachine().get(
994 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
995 const auto perfModeActual =
996 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -0800997
jiabinc8da9032021-04-28 20:42:36 +0000998 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -0800999 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +00001000 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
1001 const auto sharingModeActual =
1002 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -08001003
1004 int32_t xrunCount = -1;
1005 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1006 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
1007
jiabin92c9a522021-02-12 22:37:42 +00001008 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -08001009 // TODO: only routed device id is logged, but no device type
1010
jiabin97247ea2021-04-07 00:33:38 +00001011 std::string formatAppStr;
1012 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +00001013 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +00001014 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -08001015
1016 std::string formatDeviceStr;
1017 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1018 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1019 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1020
jiabin92c9a522021-02-12 22:37:42 +00001021 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001022 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1023 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001024
jiabinc4c331c2021-03-23 17:11:01 +00001025 int32_t sampleRate = 0;
1026 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1027 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1028
1029 std::string contentTypeStr;
1030 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1031 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1032 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1033
jiabinc8da9032021-04-28 20:42:36 +00001034 std::string sharingModeRequestedStr;
1035 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1036 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1037 const auto sharingModeRequested =
1038 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1039
jiabin515eb092020-11-18 17:55:52 -08001040 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001041 << " path:" << path
1042 << " direction:" << direction << "(" << directionStr << ")"
1043 << " frames_per_burst:" << framesPerBurst
1044 << " buffer_size:" << bufferSizeInFrames
1045 << " buffer_capacity:" << bufferCapacityInFrames
1046 << " channel_count:" << channelCount
1047 << " total_frames_transferred:" << totalFramesTransferred
1048 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001049 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001050 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001051 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001052 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001053 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001054 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001055 << " log_session_id: " << logSessionId
1056 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001057 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1058 << " sharing_requested:" << sharingModeRequested
1059 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001060
jiabin92c9a522021-02-12 22:37:42 +00001061 if (mAudioAnalytics.mDeliverStatistics) {
1062 android::util::BytesField bf_serialized(
1063 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1064 const auto result = sendToStatsd(
1065 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001066 , path
1067 , direction
1068 , framesPerBurst
1069 , bufferSizeInFrames
1070 , bufferCapacityInFrames
1071 , channelCount
1072 , totalFramesTransferred
1073 , perfModeRequested
1074 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001075 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001076 , xrunCount
1077 , bf_serialized
1078 , formatApp
1079 , formatDevice
1080 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001081 , sampleRate
1082 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001083 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001084 );
1085 std::stringstream ss;
1086 ss << "result:" << result;
1087 const auto fieldsStr = printFields(AAudioStreamFields,
1088 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001089 , path
1090 , direction
1091 , framesPerBurst
1092 , bufferSizeInFrames
1093 , bufferCapacityInFrames
1094 , channelCount
1095 , totalFramesTransferred
1096 , perfModeRequested
1097 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001098 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001099 , xrunCount
1100 , serializedDeviceTypes.c_str()
1101 , formatApp
1102 , formatDevice
1103 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001104 , sampleRate
1105 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001106 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001107 );
1108 ss << " " << fieldsStr;
1109 std::string str = ss.str();
1110 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001111 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001112 }
jiabin515eb092020-11-18 17:55:52 -08001113}
1114
Andy Hung3ab1b322020-05-18 10:47:31 -07001115} // namespace android::mediametrics