blob: 8e1af209a998b688694caed0de0c1a51e82f2031 [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
Andy Hung06f3aba2019-12-03 16:36:42 -080027
Andy Hung1ea842e2020-05-18 10:47:31 -070028#include "AudioTypes.h" // string to int conversions
29#include "MediaMetricsService.h" // package info
30#include "StringUtils.h"
31
32#define PROP_AUDIO_ANALYTICS_CLOUD_ENABLED "persist.audio.analytics.cloud.enabled"
33
Andy Hunga629bd12020-06-05 16:03:53 -070034namespace android::mediametrics {
Andy Hung1ea842e2020-05-18 10:47:31 -070035
Andy Hunga629bd12020-06-05 16:03:53 -070036// Enable for testing of delivery to statsd. Caution if this is enabled, all protos MUST exist.
Andy Hunga0a5ad22020-06-12 09:30:34 -070037#define STATSD_ENABLE
Andy Hung1ea842e2020-05-18 10:47:31 -070038
Andy Hunga629bd12020-06-05 16:03:53 -070039#ifdef STATSD_ENABLE
40#define CONDITION(INT_VALUE) (INT_VALUE) // allow value
Andy Hung1ea842e2020-05-18 10:47:31 -070041#else
Andy Hunga629bd12020-06-05 16:03:53 -070042#define CONDITION(INT_VALUE) (int(0)) // mask value since the proto may not be defined yet.
Andy Hung1ea842e2020-05-18 10:47:31 -070043#endif
44
Andy Hunga629bd12020-06-05 16:03:53 -070045// Maximum length of a device name.
Andy Hung3deef2b2020-07-17 12:58:54 -070046// static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32; // unused since we suppress
Andy Hung06f3aba2019-12-03 16:36:42 -080047
Andy Hunga629bd12020-06-05 16:03:53 -070048// Transmit Enums to statsd in integer or strings (this must match the atoms.proto)
49static constexpr bool STATSD_USE_INT_FOR_ENUM = false;
50
51// derive types based on integer or strings.
52using short_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int32_t, std::string>;
53using long_enum_type_t = std::conditional_t<STATSD_USE_INT_FOR_ENUM, int64_t, std::string>;
54
55// Convert std::string to char *
56template <typename T>
57auto ENUM_EXTRACT(const T& x) {
58 if constexpr (std::is_same_v<std::decay_t<T>, std::string>) {
59 return x.c_str();
60 } else {
61 return x;
62 }
63}
64
65static constexpr const auto LOG_LEVEL = android::base::VERBOSE;
66
Andy Hungb18f5062020-06-18 23:10:08 -070067static constexpr int PREVIOUS_STATE_EXPIRE_SEC = 60 * 60; // 1 hour.
68
Andy Hung3deef2b2020-07-17 12:58:54 -070069static constexpr const char * SUPPRESSED = "SUPPRESSED";
70
Andy Hunga629bd12020-06-05 16:03:53 -070071/*
72 * For logging purposes, we list all of the MediaMetrics atom fields,
73 * which can then be associated with consecutive arguments to the statsd write.
74 */
75
76static constexpr const char * const AudioRecordDeviceUsageFields[] = {
77 "mediametrics_audiorecorddeviceusage_reported", // proto number
78 "devices",
79 "device_names",
80 "device_time_nanos",
81 "encoding",
82 "frame_count",
83 "interval_count",
84 "sample_rate",
85 "flags",
86 "package_name",
87 "selected_device_id",
88 "caller",
89 "source",
Andy Hungcbcfaa22021-02-23 13:54:49 -080090 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -070091};
92
93static constexpr const char * const AudioThreadDeviceUsageFields[] = {
94 "mediametrics_audiothreaddeviceusage_reported",
95 "devices",
96 "device_names",
97 "device_time_nanos",
98 "encoding",
99 "frame_count",
100 "interval_count",
101 "sample_rate",
102 "flags",
103 "xruns",
104 "type",
105};
106
107static constexpr const char * const AudioTrackDeviceUsageFields[] = {
108 "mediametrics_audiotrackdeviceusage_reported",
109 "devices",
110 "device_names",
111 "device_time_nanos",
112 "encoding",
113 "frame_count",
114 "interval_count",
115 "sample_rate",
116 "flags",
117 "xruns",
118 "package_name",
119 "device_latency_millis",
120 "device_startup_millis",
121 "device_volume",
122 "selected_device_id",
123 "stream_type",
124 "usage",
125 "content_type",
126 "caller",
127 "traits",
Andy Hungcbcfaa22021-02-23 13:54:49 -0800128 "log_session_id",
Andy Hunga629bd12020-06-05 16:03:53 -0700129};
130
131static constexpr const char * const AudioDeviceConnectionFields[] = {
132 "mediametrics_audiodeviceconnection_reported",
133 "input_devices",
134 "output_devices",
135 "device_names",
136 "result",
137 "time_to_connect_millis",
138 "connection_count",
139};
140
jiabin92c9a522021-02-12 22:37:42 +0000141static constexpr const char * const AAudioStreamFields[] {
142 "mediametrics_aaudiostream_reported",
jiabin92c9a522021-02-12 22:37:42 +0000143 "path",
144 "direction",
145 "frames_per_burst",
146 "buffer_size",
147 "buffer_capacity",
148 "channel_count",
149 "total_frames_transferred",
150 "perf_mode_requested",
151 "perf_mode_actual",
152 "sharing",
153 "xrun_count",
154 "device_type",
155 "format_app",
156 "format_device",
157 "log_session_id",
jiabinc4c331c2021-03-23 17:11:01 +0000158 "sample_rate",
159 "content_type",
jiabin92c9a522021-02-12 22:37:42 +0000160};
161
162/**
163 * printFields is a helper method that prints the fields and corresponding values
164 * in a human readable style.
165 */
166template <size_t N, typename ...Types>
167std::string printFields(const char * const (& fields)[N], Types ... args)
168{
169 std::stringstream ss;
170 ss << " { ";
171 stringutils::fieldPrint(ss, fields, args...);
172 ss << "}";
173 return ss.str();
174}
175
176/**
177 * sendToStatsd is a helper method that sends the arguments to statsd
178 */
179template <typename ...Types>
180int sendToStatsd(Types ... args)
181{
182 int result = 0;
183
184#ifdef STATSD_ENABLE
185 result = android::util::stats_write(args...);
186#endif
187 return result;
188}
jiabin515eb092020-11-18 17:55:52 -0800189
Andy Hunga629bd12020-06-05 16:03:53 -0700190/**
191 * sendToStatsd is a helper method that sends the arguments to statsd
192 * and returns a pair { result, summary_string }.
193 */
194template <size_t N, typename ...Types>
195std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
196{
197 int result = 0;
198 std::stringstream ss;
199
200#ifdef STATSD_ENABLE
201 result = android::util::stats_write(args...);
202 ss << "result:" << result;
203#endif
204 ss << " { ";
205 stringutils::fieldPrint(ss, fields, args...);
206 ss << "}";
207 return { result, ss.str() };
208}
Andy Hung06f3aba2019-12-03 16:36:42 -0800209
210AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -0700211 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -0800212{
Andy Hunga629bd12020-06-05 16:03:53 -0700213 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800214 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800215
216 // Add action to save AnalyticsState if audioserver is restarted.
217 // This triggers on an item of "audio.flinger"
218 // with a property "event" set to "AudioFlinger" (the constructor).
219 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800220 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
221 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800222 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800223 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
224 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800225 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
226 *mAnalyticsState.get()));
227 // Note: get returns shared_ptr temp, whose lifetime is extended
228 // to end of full expression.
229 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800230 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700231
232 // Set up a timer to expire the previous audio state to save space.
233 // Use the transaction log size as a cookie to see if it is the
234 // same as before. A benign race is possible where a state is cleared early.
235 const size_t size = mPreviousAnalyticsState->transactionLog().size();
236 mTimedAction.postIn(
237 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
238 if (mPreviousAnalyticsState->transactionLog().size() == size) {
239 ALOGD("expiring previous audio state after %d seconds.",
240 PREVIOUS_STATE_EXPIRE_SEC);
241 mPreviousAnalyticsState->clear(); // removes data from the state.
242 }
243 });
Andy Hungea186fa2020-01-09 18:13:15 -0800244 }));
245
jiabin97247ea2021-04-07 00:33:38 +0000246 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800247 mActions.addAction(
248 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
249 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
250 std::make_shared<AnalyticsActions::Function>(
251 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
252 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
253 }));
254
jiabin97247ea2021-04-07 00:33:38 +0000255 // Handle legacy aaudio capture stream statistics
256 mActions.addAction(
257 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
258 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
259 std::make_shared<AnalyticsActions::Function>(
260 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
261 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
262 }));
263
jiabin515eb092020-11-18 17:55:52 -0800264 // Handle mmap aaudio stream statistics
265 mActions.addAction(
266 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
267 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
268 std::make_shared<AnalyticsActions::Function>(
269 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
270 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
271 }));
272
Andy Hungea840382020-05-05 21:50:17 -0700273 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800274 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700275 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
276 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800277 std::make_shared<AnalyticsActions::Function>(
278 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700279 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800280 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700281
282 // Handle device use thread statistics
283 mActions.addAction(
284 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
285 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
286 std::make_shared<AnalyticsActions::Function>(
287 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700288 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700289 }));
290
291 // Handle device use track statistics
292 mActions.addAction(
293 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
294 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
295 std::make_shared<AnalyticsActions::Function>(
296 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700297 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700298 }));
299
Andy Hungea840382020-05-05 21:50:17 -0700300
301 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700302
303 // We track connections (not disconnections) for the time to connect.
304 // TODO: consider BT requests in their A2dp service
305 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
306 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
307 // AudioDeviceBroker.postA2dpActiveDeviceChange
308 mActions.addAction(
309 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700310 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700311 std::make_shared<AnalyticsActions::Function>(
312 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
313 mDeviceConnection.a2dpConnected(item);
314 }));
315 // If audio is active, we expect to see a createAudioPatch after the device is connected.
316 mActions.addAction(
317 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
318 std::string("createAudioPatch"),
319 std::make_shared<AnalyticsActions::Function>(
320 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
321 mDeviceConnection.createPatch(item);
322 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800323
Andy Hungea840382020-05-05 21:50:17 -0700324 // Called from BT service
325 mActions.addAction(
326 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
327 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
328 "." AMEDIAMETRICS_PROP_STATE,
329 "connected",
330 std::make_shared<AnalyticsActions::Function>(
331 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
332 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
333 }));
334
Joey Poomarin52989982020-03-05 17:40:49 +0800335 // Handle power usage
336 mActions.addAction(
337 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
338 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
339 std::make_shared<AnalyticsActions::Function>(
340 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
341 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
342 }));
343
344 mActions.addAction(
345 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
346 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
347 std::make_shared<AnalyticsActions::Function>(
348 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
349 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
350 }));
351
352 mActions.addAction(
353 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
354 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
355 std::make_shared<AnalyticsActions::Function>(
356 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
357 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
358 mAudioPowerUsage.checkMode(item);
359 }));
360
361 mActions.addAction(
362 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
363 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
364 std::make_shared<AnalyticsActions::Function>(
365 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
366 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
367 mAudioPowerUsage.checkVoiceVolume(item);
368 }));
369
370 mActions.addAction(
371 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
372 std::string("createAudioPatch"),
373 std::make_shared<AnalyticsActions::Function>(
374 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
375 mAudioPowerUsage.checkCreatePatch(item);
376 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800377}
378
379AudioAnalytics::~AudioAnalytics()
380{
381 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700382 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800383}
384
385status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800386 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800387{
Andy Hungea186fa2020-01-09 18:13:15 -0800388 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800389 status_t status = mAnalyticsState->submit(item, isTrusted);
390 if (status != NO_ERROR) return status; // may not be permitted.
391
392 // Only if the item was successfully submitted (permission)
393 // do we check triggered actions.
394 checkActions(item);
395 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800396}
397
Andy Hung709b91e2020-04-04 14:23:36 -0700398std::pair<std::string, int32_t> AudioAnalytics::dump(
399 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800400{
401 std::stringstream ss;
402 int32_t ll = lines;
403
404 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700405 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700406 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800407 ll -= l;
408 }
409 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800410 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800411 --ll;
412 }
413 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700414 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700415 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800416 ll -= l;
417 }
Joey Poomarin52989982020-03-05 17:40:49 +0800418
Andy Hunga629bd12020-06-05 16:03:53 -0700419 if (ll > 0) {
420 // Print the statsd atoms we sent out.
421 const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
422 const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
423 if ((size_t)ll >= n) {
424 if (n == 1) {
425 ss << "Statsd atoms: empty or truncated\n";
426 } else {
427 ss << "Statsd atoms:\n" << statsd;
428 }
Andy Hungc14ee142021-03-10 16:39:02 -0800429 ll -= (int32_t)n;
Andy Hunga629bd12020-06-05 16:03:53 -0700430 }
431 }
432
Joey Poomarin52989982020-03-05 17:40:49 +0800433 if (ll > 0 && prefix == nullptr) {
434 auto [s, l] = mAudioPowerUsage.dump(ll);
435 ss << s;
436 ll -= l;
437 }
Andy Hunga629bd12020-06-05 16:03:53 -0700438
Andy Hung06f3aba2019-12-03 16:36:42 -0800439 return { ss.str(), lines - ll };
440}
441
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800442void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
443{
444 auto actions = mActions.getActionsForItem(item); // internally locked.
445 // Execute actions with no lock held.
446 for (const auto& action : actions) {
447 (*action)(item);
448 }
449}
450
Andy Hungea186fa2020-01-09 18:13:15 -0800451// HELPER METHODS
452
453std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
454{
455 int32_t threadId_int32{};
456 if (mAnalyticsState->timeMachine().get(
457 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
458 return {};
459 }
460 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
461}
462
Andy Hungce9b6632020-04-28 20:15:17 -0700463// DeviceUse helper class.
464void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700465 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700466 const std::string& key = item->getKey();
467 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700468 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
469 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
470 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700471 - 1);
472 // deliver statistics
473 int64_t deviceTimeNs = 0;
474 mAudioAnalytics.mAnalyticsState->timeMachine().get(
475 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
476 std::string encoding;
477 mAudioAnalytics.mAnalyticsState->timeMachine().get(
478 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
479 int32_t frameCount = 0;
480 mAudioAnalytics.mAnalyticsState->timeMachine().get(
481 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700482 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700483 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700484 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700485 int32_t intervalCount = 0;
486 mAudioAnalytics.mAnalyticsState->timeMachine().get(
487 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700488 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700489 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700490 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700491 int32_t sampleRate = 0;
492 mAudioAnalytics.mAnalyticsState->timeMachine().get(
493 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700494 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700495 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700496 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700497
Andy Hungea840382020-05-05 21:50:17 -0700498 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700499 // Accumulate the bit flags for input and output devices.
500 std::stringstream oss;
501 long_enum_type_t outputDeviceBits{};
502 { // compute outputDevices
503 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700504 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700505 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
506 oss << device;
507 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700508 }
509 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700510 const std::string outputDevices = oss.str();
511
512 std::stringstream iss;
513 long_enum_type_t inputDeviceBits{};
514 { // compute inputDevices
515 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
516 for (const auto& [device, addr] : devaddrvec) {
517 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
518 iss << device;
519 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
520 }
521 }
522 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700523
524 // Get connected device name if from bluetooth.
525 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700526
527 std::string inputDeviceNames; // not filled currently.
528 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700529 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
530 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700531 outputDeviceNames = SUPPRESSED;
532#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700533 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700534 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700535 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700536 stringutils::replace(outputDeviceNames, "|", '?');
537 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
538 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
539 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700540#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700541 }
542
Andy Hungea840382020-05-05 21:50:17 -0700543 switch (itemType) {
544 case RECORD: {
545 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700546 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
547 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700548
Andy Hungea840382020-05-05 21:50:17 -0700549 std::string packageName;
550 int64_t versionCode = 0;
551 int32_t uid = -1;
552 mAudioAnalytics.mAnalyticsState->timeMachine().get(
553 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
554 if (uid != -1) {
555 std::tie(packageName, versionCode) =
556 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
557 }
558
559 int32_t selectedDeviceId = 0;
560 mAudioAnalytics.mAnalyticsState->timeMachine().get(
561 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
562 std::string source;
563 mAudioAnalytics.mAnalyticsState->timeMachine().get(
564 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800565 // Android S
566 std::string logSessionId;
567 mAudioAnalytics.mAnalyticsState->timeMachine().get(
568 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700569
Andy Hung1ea842e2020-05-18 10:47:31 -0700570 const auto callerNameForStats =
571 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
572 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
573 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
574 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800575 // Android S
576 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700577
Andy Hunga629bd12020-06-05 16:03:53 -0700578 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700579 << " id:" << id
580 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700581 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700582 << " deviceTimeNs:" << deviceTimeNs
583 << " encoding:" << encoding << "(" << encodingForStats
584 << ") frameCount:" << frameCount
585 << " intervalCount:" << intervalCount
586 << " sampleRate:" << sampleRate
587 << " flags:" << flags << "(" << flagsForStats
588 << ") packageName:" << packageName
589 << " selectedDeviceId:" << selectedDeviceId
590 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800591 << ") source:" << source << "(" << sourceForStats
592 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
593 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700594 if (clientCalled // only log if client app called AudioRecord.
595 && mAudioAnalytics.mDeliverStatistics) {
596 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
597 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700598 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700599 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700600 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700601 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700602 , frameCount
603 , intervalCount
604 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700605 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700606
607 , packageName.c_str()
608 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700609 , ENUM_EXTRACT(callerNameForStats)
610 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800611 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700612 );
Andy Hunga629bd12020-06-05 16:03:53 -0700613 ALOGV("%s: statsd %s", __func__, str.c_str());
614 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700615 }
Andy Hungea840382020-05-05 21:50:17 -0700616 } break;
617 case THREAD: {
618 std::string type;
619 mAudioAnalytics.mAnalyticsState->timeMachine().get(
620 key, AMEDIAMETRICS_PROP_TYPE, &type);
621 int32_t underrun = 0; // zero for record types
622 mAudioAnalytics.mAnalyticsState->timeMachine().get(
623 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700624
625 const bool isInput = types::isInputThreadType(type);
626 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
627 const auto flagsForStats =
628 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
629 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
630 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
631
Andy Hunga629bd12020-06-05 16:03:53 -0700632 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700633 << " id:" << id
634 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
635 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700636 << ") inputDeviceNames:" << inputDeviceNames
637 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700638 << " deviceTimeNs:" << deviceTimeNs
639 << " encoding:" << encoding << "(" << encodingForStats
640 << ") frameCount:" << frameCount
641 << " intervalCount:" << intervalCount
642 << " sampleRate:" << sampleRate
643 << " underrun:" << underrun
644 << " flags:" << flags << "(" << flagsForStats
645 << ") type:" << type << "(" << typeForStats
646 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700647 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700648 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
649 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
650 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
651 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700652 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700653 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700654 , frameCount
655 , intervalCount
656 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700657 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700658 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700659 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700660 );
Andy Hunga629bd12020-06-05 16:03:53 -0700661 ALOGV("%s: statsd %s", __func__, str.c_str());
662 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700663 }
Andy Hungea840382020-05-05 21:50:17 -0700664 } break;
665 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700666 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700667 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
668 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
669
Andy Hungce9b6632020-04-28 20:15:17 -0700670 std::string contentType;
671 mAudioAnalytics.mAnalyticsState->timeMachine().get(
672 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
673 double deviceLatencyMs = 0.;
674 mAudioAnalytics.mAnalyticsState->timeMachine().get(
675 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
676 double deviceStartupMs = 0.;
677 mAudioAnalytics.mAnalyticsState->timeMachine().get(
678 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
679 double deviceVolume = 0.;
680 mAudioAnalytics.mAnalyticsState->timeMachine().get(
681 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
682 std::string packageName;
683 int64_t versionCode = 0;
684 int32_t uid = -1;
685 mAudioAnalytics.mAnalyticsState->timeMachine().get(
686 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
687 if (uid != -1) {
688 std::tie(packageName, versionCode) =
689 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
690 }
691 double playbackPitch = 0.;
692 mAudioAnalytics.mAnalyticsState->timeMachine().get(
693 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
694 double playbackSpeed = 0.;
695 mAudioAnalytics.mAnalyticsState->timeMachine().get(
696 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
697 int32_t selectedDeviceId = 0;
698 mAudioAnalytics.mAnalyticsState->timeMachine().get(
699 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700700 std::string streamType;
701 mAudioAnalytics.mAnalyticsState->timeMachine().get(
702 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700703 std::string traits;
704 mAudioAnalytics.mAnalyticsState->timeMachine().get(
705 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700706 int32_t underrun = 0;
707 mAudioAnalytics.mAnalyticsState->timeMachine().get(
708 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700709 std::string usage;
710 mAudioAnalytics.mAnalyticsState->timeMachine().get(
711 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800712 // Android S
713 std::string logSessionId;
714 mAudioAnalytics.mAnalyticsState->timeMachine().get(
715 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700716
Andy Hung1ea842e2020-05-18 10:47:31 -0700717 const auto callerNameForStats =
718 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
719 const auto contentTypeForStats =
720 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
721 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
722 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
723 const auto streamTypeForStats =
724 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700725 const auto traitsForStats =
726 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700727 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800728 // Android S
729 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700730
Andy Hunga629bd12020-06-05 16:03:53 -0700731 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700732 << " id:" << id
733 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700734 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700735 << " deviceTimeNs:" << deviceTimeNs
736 << " encoding:" << encoding << "(" << encodingForStats
737 << ") frameCount:" << frameCount
738 << " intervalCount:" << intervalCount
739 << " sampleRate:" << sampleRate
740 << " underrun:" << underrun
741 << " flags:" << flags << "(" << flagsForStats
742 << ") callerName:" << callerName << "(" << callerNameForStats
743 << ") contentType:" << contentType << "(" << contentTypeForStats
744 << ") deviceLatencyMs:" << deviceLatencyMs
745 << " deviceStartupMs:" << deviceStartupMs
746 << " deviceVolume:" << deviceVolume
747 << " packageName:" << packageName
748 << " playbackPitch:" << playbackPitch
749 << " playbackSpeed:" << playbackSpeed
750 << " selectedDeviceId:" << selectedDeviceId
751 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700752 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700753 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800754 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700755 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700756 if (clientCalled // only log if client app called AudioTracks
757 && mAudioAnalytics.mDeliverStatistics) {
758 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
759 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700760 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700761 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700762 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700763 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700764 , frameCount
765 , intervalCount
766 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700767 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700768 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700769 , packageName.c_str()
770 , (float)deviceLatencyMs
771 , (float)deviceStartupMs
772 , (float)deviceVolume
773 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700774 , ENUM_EXTRACT(streamTypeForStats)
775 , ENUM_EXTRACT(usageForStats)
776 , ENUM_EXTRACT(contentTypeForStats)
777 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700778 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800779 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700780 );
Andy Hunga629bd12020-06-05 16:03:53 -0700781 ALOGV("%s: statsd %s", __func__, str.c_str());
782 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700783 }
Andy Hungea840382020-05-05 21:50:17 -0700784 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700785 }
786
787 // Report this as needed.
788 if (isBluetooth) {
789 // report this for Bluetooth
790 }
791}
792
793// DeviceConnection helper class.
794void AudioAnalytics::DeviceConnection::a2dpConnected(
795 const std::shared_ptr<const android::mediametrics::Item> &item) {
796 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700797 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700798 {
799 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700800 mA2dpConnectionServiceNs = atNs;
801 ++mA2dpConnectionServices;
802
803 if (mA2dpConnectionRequestNs == 0) {
804 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
805 }
806 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700807 }
808 std::string name;
809 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700810 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
811 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700812}
813
814void AudioAnalytics::DeviceConnection::createPatch(
815 const std::shared_ptr<const android::mediametrics::Item> &item) {
816 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700817 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700818 const std::string& key = item->getKey();
819 std::string outputDevices;
820 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700821 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700822 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700823 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700824 if (mA2dpConnectionRequestNs == 0) {
825 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700826 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700827 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700828 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700829 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700830
Andy Hungea840382020-05-05 21:50:17 -0700831 mA2dpConnectionRequestNs = 0;
832 mA2dpConnectionServiceNs = 0;
833 ++mA2dpConnectionSuccesses;
834
Andy Hungc14ee142021-03-10 16:39:02 -0800835 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -0700836
837 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
838 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
839
Andy Hunga629bd12020-06-05 16:03:53 -0700840 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700841 << " A2DP SUCCESS"
842 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700843 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700844 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700845 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700846 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700847
848 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
849 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700850 , ENUM_EXTRACT(inputDeviceBits)
851 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700852 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700853 , types::DEVICE_CONNECTION_RESULT_SUCCESS
854 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700855 , /* connection_count */ 1
856 );
Andy Hunga629bd12020-06-05 16:03:53 -0700857 ALOGV("%s: statsd %s", __func__, str.c_str());
858 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700859 }
Andy Hungce9b6632020-04-28 20:15:17 -0700860 }
861}
862
Andy Hungea840382020-05-05 21:50:17 -0700863// Called through AudioManager when the BT service wants to enable
864void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
865 const std::shared_ptr<const android::mediametrics::Item> &item) {
866 const int64_t atNs = item->getTimestamp();
867 const std::string& key = item->getKey();
868 std::string state;
869 item->get(AMEDIAMETRICS_PROP_STATE, &state);
870 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700871
872 std::string name;
873 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700874 {
875 std::lock_guard l(mLock);
876 mA2dpConnectionRequestNs = atNs;
877 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700878 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700879 }
Andy Hunga629bd12020-06-05 16:03:53 -0700880 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
881 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700882 // TODO: attempt to cancel a timed event, rather than let it expire.
883 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
884}
885
Andy Hungce9b6632020-04-28 20:15:17 -0700886void AudioAnalytics::DeviceConnection::expire() {
887 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700888 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700889
Andy Hung1ea842e2020-05-18 10:47:31 -0700890 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700891 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
892 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
893
Andy Hungea840382020-05-05 21:50:17 -0700894 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700895 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700896
Andy Hunga629bd12020-06-05 16:03:53 -0700897 LOG(LOG_LEVEL) << "A2DP CANCEL"
898 << " outputDevices:" << outputDeviceBits
899 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700900 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700901 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
902 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700903 , ENUM_EXTRACT(inputDeviceBits)
904 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700905 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700906 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700907 , /* connection_time_ms */ 0.f
908 , /* connection_count */ 1
909 );
Andy Hunga629bd12020-06-05 16:03:53 -0700910 ALOGV("%s: statsd %s", __func__, str.c_str());
911 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700912 }
Andy Hungea840382020-05-05 21:50:17 -0700913 return;
914 }
915
916 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
917 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700918 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700919 mA2dpConnectionRequestNs = 0;
920 mA2dpConnectionServiceNs = 0;
921 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700922
Andy Hunga629bd12020-06-05 16:03:53 -0700923 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
924 << " outputDevices:" << outputDeviceBits
925 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700926 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700927 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
928 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700929 , ENUM_EXTRACT(inputDeviceBits)
930 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700931 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700932 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700933 , /* connection_time_ms */ 0.f
934 , /* connection_count */ 1
935 );
Andy Hunga629bd12020-06-05 16:03:53 -0700936 ALOGV("%s: statsd %s", __func__, str.c_str());
937 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700938 }
Andy Hungce9b6632020-04-28 20:15:17 -0700939}
940
jiabin515eb092020-11-18 17:55:52 -0800941void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
942 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
943 const std::string& key = item->getKey();
944
jiabin515eb092020-11-18 17:55:52 -0800945 std::string directionStr;
946 mAudioAnalytics.mAnalyticsState->timeMachine().get(
947 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
948 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
949
950 int32_t framesPerBurst = -1;
951 mAudioAnalytics.mAnalyticsState->timeMachine().get(
952 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
953
954 int32_t bufferSizeInFrames = -1;
955 mAudioAnalytics.mAnalyticsState->timeMachine().get(
956 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
957
958 int32_t bufferCapacityInFrames = -1;
959 mAudioAnalytics.mAnalyticsState->timeMachine().get(
960 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
961
962 int32_t channelCount = -1;
963 mAudioAnalytics.mAnalyticsState->timeMachine().get(
964 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
965
966 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +0000967 mAudioAnalytics.mAnalyticsState->timeMachine().get(
968 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -0800969
970 std::string perfModeRequestedStr;
971 mAudioAnalytics.mAnalyticsState->timeMachine().get(
972 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
973 const auto perfModeRequested =
974 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
975
jiabin97247ea2021-04-07 00:33:38 +0000976 std::string perfModeActualStr;
977 mAudioAnalytics.mAnalyticsState->timeMachine().get(
978 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
979 const auto perfModeActual =
980 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -0800981
982 std::string sharingModeStr;
983 mAudioAnalytics.mAnalyticsState->timeMachine().get(
984 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeStr);
985 const auto sharingMode = types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeStr);
986
987 int32_t xrunCount = -1;
988 mAudioAnalytics.mAnalyticsState->timeMachine().get(
989 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
990
jiabin92c9a522021-02-12 22:37:42 +0000991 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -0800992 // TODO: only routed device id is logged, but no device type
993
jiabin97247ea2021-04-07 00:33:38 +0000994 std::string formatAppStr;
995 mAudioAnalytics.mAnalyticsState->timeMachine().get(
996 key, AMEDIAMETRICS_PROP_ENCODINGREQUESTED, &formatAppStr);
997 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -0800998
999 std::string formatDeviceStr;
1000 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1001 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
1002 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
1003
jiabin92c9a522021-02-12 22:37:42 +00001004 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001005 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1006 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001007
jiabinc4c331c2021-03-23 17:11:01 +00001008 int32_t sampleRate = 0;
1009 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1010 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1011
1012 std::string contentTypeStr;
1013 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1014 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1015 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1016
jiabin515eb092020-11-18 17:55:52 -08001017 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001018 << " path:" << path
1019 << " direction:" << direction << "(" << directionStr << ")"
1020 << " frames_per_burst:" << framesPerBurst
1021 << " buffer_size:" << bufferSizeInFrames
1022 << " buffer_capacity:" << bufferCapacityInFrames
1023 << " channel_count:" << channelCount
1024 << " total_frames_transferred:" << totalFramesTransferred
1025 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001026 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001027 << " sharing:" << sharingMode << "(" << sharingModeStr << ")"
1028 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001029 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001030 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001031 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001032 << " log_session_id: " << logSessionId
1033 << " sample_rate: " << sampleRate
1034 << " content_type: " << contentType << "(" << contentTypeStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001035
jiabin92c9a522021-02-12 22:37:42 +00001036 if (mAudioAnalytics.mDeliverStatistics) {
1037 android::util::BytesField bf_serialized(
1038 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1039 const auto result = sendToStatsd(
1040 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001041 , path
1042 , direction
1043 , framesPerBurst
1044 , bufferSizeInFrames
1045 , bufferCapacityInFrames
1046 , channelCount
1047 , totalFramesTransferred
1048 , perfModeRequested
1049 , perfModeActual
1050 , sharingMode
1051 , xrunCount
1052 , bf_serialized
1053 , formatApp
1054 , formatDevice
1055 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001056 , sampleRate
1057 , contentType
jiabin92c9a522021-02-12 22:37:42 +00001058 );
1059 std::stringstream ss;
1060 ss << "result:" << result;
1061 const auto fieldsStr = printFields(AAudioStreamFields,
1062 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001063 , path
1064 , direction
1065 , framesPerBurst
1066 , bufferSizeInFrames
1067 , bufferCapacityInFrames
1068 , channelCount
1069 , totalFramesTransferred
1070 , perfModeRequested
1071 , perfModeActual
1072 , sharingMode
1073 , xrunCount
1074 , serializedDeviceTypes.c_str()
1075 , formatApp
1076 , formatDevice
1077 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001078 , sampleRate
1079 , contentType
jiabin92c9a522021-02-12 22:37:42 +00001080 );
1081 ss << " " << fieldsStr;
1082 std::string str = ss.str();
1083 ALOGV("%s: statsd %s", __func__, str.c_str());
1084 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
1085 }
jiabin515eb092020-11-18 17:55:52 -08001086}
1087
Andy Hung3ab1b322020-05-18 10:47:31 -07001088} // namespace android::mediametrics