blob: 96309072737bd49981a988c18854ade6e9560b8b [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",
143 "caller_name",
144 "path",
145 "direction",
146 "frames_per_burst",
147 "buffer_size",
148 "buffer_capacity",
149 "channel_count",
150 "total_frames_transferred",
151 "perf_mode_requested",
152 "perf_mode_actual",
153 "sharing",
154 "xrun_count",
155 "device_type",
156 "format_app",
157 "format_device",
158 "log_session_id",
159};
160
161/**
162 * printFields is a helper method that prints the fields and corresponding values
163 * in a human readable style.
164 */
165template <size_t N, typename ...Types>
166std::string printFields(const char * const (& fields)[N], Types ... args)
167{
168 std::stringstream ss;
169 ss << " { ";
170 stringutils::fieldPrint(ss, fields, args...);
171 ss << "}";
172 return ss.str();
173}
174
175/**
176 * sendToStatsd is a helper method that sends the arguments to statsd
177 */
178template <typename ...Types>
179int sendToStatsd(Types ... args)
180{
181 int result = 0;
182
183#ifdef STATSD_ENABLE
184 result = android::util::stats_write(args...);
185#endif
186 return result;
187}
jiabin515eb092020-11-18 17:55:52 -0800188
Andy Hunga629bd12020-06-05 16:03:53 -0700189/**
190 * sendToStatsd is a helper method that sends the arguments to statsd
191 * and returns a pair { result, summary_string }.
192 */
193template <size_t N, typename ...Types>
194std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
195{
196 int result = 0;
197 std::stringstream ss;
198
199#ifdef STATSD_ENABLE
200 result = android::util::stats_write(args...);
201 ss << "result:" << result;
202#endif
203 ss << " { ";
204 stringutils::fieldPrint(ss, fields, args...);
205 ss << "}";
206 return { result, ss.str() };
207}
Andy Hung06f3aba2019-12-03 16:36:42 -0800208
209AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -0700210 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -0800211{
Andy Hunga629bd12020-06-05 16:03:53 -0700212 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800213 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800214
215 // Add action to save AnalyticsState if audioserver is restarted.
216 // This triggers on an item of "audio.flinger"
217 // with a property "event" set to "AudioFlinger" (the constructor).
218 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800219 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
220 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800221 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800222 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
223 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800224 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
225 *mAnalyticsState.get()));
226 // Note: get returns shared_ptr temp, whose lifetime is extended
227 // to end of full expression.
228 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800229 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700230
231 // Set up a timer to expire the previous audio state to save space.
232 // Use the transaction log size as a cookie to see if it is the
233 // same as before. A benign race is possible where a state is cleared early.
234 const size_t size = mPreviousAnalyticsState->transactionLog().size();
235 mTimedAction.postIn(
236 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
237 if (mPreviousAnalyticsState->transactionLog().size() == size) {
238 ALOGD("expiring previous audio state after %d seconds.",
239 PREVIOUS_STATE_EXPIRE_SEC);
240 mPreviousAnalyticsState->clear(); // removes data from the state.
241 }
242 });
Andy Hungea186fa2020-01-09 18:13:15 -0800243 }));
244
jiabin515eb092020-11-18 17:55:52 -0800245 // Handle legacy aaudio stream statistics
246 mActions.addAction(
247 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
248 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
249 std::make_shared<AnalyticsActions::Function>(
250 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
251 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
252 }));
253
254 // Handle mmap aaudio stream statistics
255 mActions.addAction(
256 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
257 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
258 std::make_shared<AnalyticsActions::Function>(
259 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
260 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
261 }));
262
Andy Hungea840382020-05-05 21:50:17 -0700263 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800264 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700265 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
266 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800267 std::make_shared<AnalyticsActions::Function>(
268 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700269 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800270 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700271
272 // Handle device use thread statistics
273 mActions.addAction(
274 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
275 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
276 std::make_shared<AnalyticsActions::Function>(
277 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700278 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700279 }));
280
281 // Handle device use track statistics
282 mActions.addAction(
283 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
284 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
285 std::make_shared<AnalyticsActions::Function>(
286 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700287 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700288 }));
289
Andy Hungea840382020-05-05 21:50:17 -0700290
291 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700292
293 // We track connections (not disconnections) for the time to connect.
294 // TODO: consider BT requests in their A2dp service
295 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
296 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
297 // AudioDeviceBroker.postA2dpActiveDeviceChange
298 mActions.addAction(
299 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700300 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700301 std::make_shared<AnalyticsActions::Function>(
302 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
303 mDeviceConnection.a2dpConnected(item);
304 }));
305 // If audio is active, we expect to see a createAudioPatch after the device is connected.
306 mActions.addAction(
307 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
308 std::string("createAudioPatch"),
309 std::make_shared<AnalyticsActions::Function>(
310 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
311 mDeviceConnection.createPatch(item);
312 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800313
Andy Hungea840382020-05-05 21:50:17 -0700314 // Called from BT service
315 mActions.addAction(
316 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
317 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
318 "." AMEDIAMETRICS_PROP_STATE,
319 "connected",
320 std::make_shared<AnalyticsActions::Function>(
321 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
322 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
323 }));
324
Joey Poomarin52989982020-03-05 17:40:49 +0800325 // Handle power usage
326 mActions.addAction(
327 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
328 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
329 std::make_shared<AnalyticsActions::Function>(
330 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
331 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
332 }));
333
334 mActions.addAction(
335 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
336 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
337 std::make_shared<AnalyticsActions::Function>(
338 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
339 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
340 }));
341
342 mActions.addAction(
343 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
344 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
345 std::make_shared<AnalyticsActions::Function>(
346 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
347 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
348 mAudioPowerUsage.checkMode(item);
349 }));
350
351 mActions.addAction(
352 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
353 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
354 std::make_shared<AnalyticsActions::Function>(
355 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
356 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
357 mAudioPowerUsage.checkVoiceVolume(item);
358 }));
359
360 mActions.addAction(
361 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
362 std::string("createAudioPatch"),
363 std::make_shared<AnalyticsActions::Function>(
364 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
365 mAudioPowerUsage.checkCreatePatch(item);
366 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800367}
368
369AudioAnalytics::~AudioAnalytics()
370{
371 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700372 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800373}
374
375status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800376 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800377{
Andy Hungea186fa2020-01-09 18:13:15 -0800378 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800379 status_t status = mAnalyticsState->submit(item, isTrusted);
380 if (status != NO_ERROR) return status; // may not be permitted.
381
382 // Only if the item was successfully submitted (permission)
383 // do we check triggered actions.
384 checkActions(item);
385 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800386}
387
Andy Hung709b91e2020-04-04 14:23:36 -0700388std::pair<std::string, int32_t> AudioAnalytics::dump(
389 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800390{
391 std::stringstream ss;
392 int32_t ll = lines;
393
394 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700395 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700396 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800397 ll -= l;
398 }
399 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800400 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800401 --ll;
402 }
403 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700404 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700405 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800406 ll -= l;
407 }
Joey Poomarin52989982020-03-05 17:40:49 +0800408
Andy Hunga629bd12020-06-05 16:03:53 -0700409 if (ll > 0) {
410 // Print the statsd atoms we sent out.
411 const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
412 const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
413 if ((size_t)ll >= n) {
414 if (n == 1) {
415 ss << "Statsd atoms: empty or truncated\n";
416 } else {
417 ss << "Statsd atoms:\n" << statsd;
418 }
419 ll -= n;
420 }
421 }
422
Joey Poomarin52989982020-03-05 17:40:49 +0800423 if (ll > 0 && prefix == nullptr) {
424 auto [s, l] = mAudioPowerUsage.dump(ll);
425 ss << s;
426 ll -= l;
427 }
Andy Hunga629bd12020-06-05 16:03:53 -0700428
Andy Hung06f3aba2019-12-03 16:36:42 -0800429 return { ss.str(), lines - ll };
430}
431
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800432void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
433{
434 auto actions = mActions.getActionsForItem(item); // internally locked.
435 // Execute actions with no lock held.
436 for (const auto& action : actions) {
437 (*action)(item);
438 }
439}
440
Andy Hungea186fa2020-01-09 18:13:15 -0800441// HELPER METHODS
442
443std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
444{
445 int32_t threadId_int32{};
446 if (mAnalyticsState->timeMachine().get(
447 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
448 return {};
449 }
450 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
451}
452
Andy Hungce9b6632020-04-28 20:15:17 -0700453// DeviceUse helper class.
454void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700455 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700456 const std::string& key = item->getKey();
457 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700458 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
459 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
460 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700461 - 1);
462 // deliver statistics
463 int64_t deviceTimeNs = 0;
464 mAudioAnalytics.mAnalyticsState->timeMachine().get(
465 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
466 std::string encoding;
467 mAudioAnalytics.mAnalyticsState->timeMachine().get(
468 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
469 int32_t frameCount = 0;
470 mAudioAnalytics.mAnalyticsState->timeMachine().get(
471 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700472 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700473 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700474 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700475 int32_t intervalCount = 0;
476 mAudioAnalytics.mAnalyticsState->timeMachine().get(
477 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700478 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700479 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700480 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700481 int32_t sampleRate = 0;
482 mAudioAnalytics.mAnalyticsState->timeMachine().get(
483 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700484 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700485 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700486 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700487
Andy Hungea840382020-05-05 21:50:17 -0700488 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700489 // Accumulate the bit flags for input and output devices.
490 std::stringstream oss;
491 long_enum_type_t outputDeviceBits{};
492 { // compute outputDevices
493 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700494 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700495 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
496 oss << device;
497 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700498 }
499 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700500 const std::string outputDevices = oss.str();
501
502 std::stringstream iss;
503 long_enum_type_t inputDeviceBits{};
504 { // compute inputDevices
505 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
506 for (const auto& [device, addr] : devaddrvec) {
507 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
508 iss << device;
509 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
510 }
511 }
512 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700513
514 // Get connected device name if from bluetooth.
515 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700516
517 std::string inputDeviceNames; // not filled currently.
518 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700519 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
520 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700521 outputDeviceNames = SUPPRESSED;
522#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700523 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700524 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700525 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700526 stringutils::replace(outputDeviceNames, "|", '?');
527 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
528 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
529 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700530#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700531 }
532
Andy Hungea840382020-05-05 21:50:17 -0700533 switch (itemType) {
534 case RECORD: {
535 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700536 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
537 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700538
Andy Hungea840382020-05-05 21:50:17 -0700539 std::string packageName;
540 int64_t versionCode = 0;
541 int32_t uid = -1;
542 mAudioAnalytics.mAnalyticsState->timeMachine().get(
543 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
544 if (uid != -1) {
545 std::tie(packageName, versionCode) =
546 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
547 }
548
549 int32_t selectedDeviceId = 0;
550 mAudioAnalytics.mAnalyticsState->timeMachine().get(
551 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
552 std::string source;
553 mAudioAnalytics.mAnalyticsState->timeMachine().get(
554 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800555 // Android S
556 std::string logSessionId;
557 mAudioAnalytics.mAnalyticsState->timeMachine().get(
558 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700559
Andy Hung1ea842e2020-05-18 10:47:31 -0700560 const auto callerNameForStats =
561 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
562 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
563 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
564 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800565 // Android S
566 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700567
Andy Hunga629bd12020-06-05 16:03:53 -0700568 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700569 << " id:" << id
570 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700571 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700572 << " deviceTimeNs:" << deviceTimeNs
573 << " encoding:" << encoding << "(" << encodingForStats
574 << ") frameCount:" << frameCount
575 << " intervalCount:" << intervalCount
576 << " sampleRate:" << sampleRate
577 << " flags:" << flags << "(" << flagsForStats
578 << ") packageName:" << packageName
579 << " selectedDeviceId:" << selectedDeviceId
580 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800581 << ") source:" << source << "(" << sourceForStats
582 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
583 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700584 if (clientCalled // only log if client app called AudioRecord.
585 && mAudioAnalytics.mDeliverStatistics) {
586 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
587 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700588 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700589 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700590 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700591 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700592 , frameCount
593 , intervalCount
594 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700595 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700596
597 , packageName.c_str()
598 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700599 , ENUM_EXTRACT(callerNameForStats)
600 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800601 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700602 );
Andy Hunga629bd12020-06-05 16:03:53 -0700603 ALOGV("%s: statsd %s", __func__, str.c_str());
604 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700605 }
Andy Hungea840382020-05-05 21:50:17 -0700606 } break;
607 case THREAD: {
608 std::string type;
609 mAudioAnalytics.mAnalyticsState->timeMachine().get(
610 key, AMEDIAMETRICS_PROP_TYPE, &type);
611 int32_t underrun = 0; // zero for record types
612 mAudioAnalytics.mAnalyticsState->timeMachine().get(
613 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700614
615 const bool isInput = types::isInputThreadType(type);
616 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
617 const auto flagsForStats =
618 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
619 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
620 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
621
Andy Hunga629bd12020-06-05 16:03:53 -0700622 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700623 << " id:" << id
624 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
625 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700626 << ") inputDeviceNames:" << inputDeviceNames
627 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700628 << " deviceTimeNs:" << deviceTimeNs
629 << " encoding:" << encoding << "(" << encodingForStats
630 << ") frameCount:" << frameCount
631 << " intervalCount:" << intervalCount
632 << " sampleRate:" << sampleRate
633 << " underrun:" << underrun
634 << " flags:" << flags << "(" << flagsForStats
635 << ") type:" << type << "(" << typeForStats
636 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700637 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700638 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
639 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
640 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
641 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700642 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700643 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700644 , frameCount
645 , intervalCount
646 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700647 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700648 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700649 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700650 );
Andy Hunga629bd12020-06-05 16:03:53 -0700651 ALOGV("%s: statsd %s", __func__, str.c_str());
652 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700653 }
Andy Hungea840382020-05-05 21:50:17 -0700654 } break;
655 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700656 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700657 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
658 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
659
Andy Hungce9b6632020-04-28 20:15:17 -0700660 std::string contentType;
661 mAudioAnalytics.mAnalyticsState->timeMachine().get(
662 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
663 double deviceLatencyMs = 0.;
664 mAudioAnalytics.mAnalyticsState->timeMachine().get(
665 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
666 double deviceStartupMs = 0.;
667 mAudioAnalytics.mAnalyticsState->timeMachine().get(
668 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
669 double deviceVolume = 0.;
670 mAudioAnalytics.mAnalyticsState->timeMachine().get(
671 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
672 std::string packageName;
673 int64_t versionCode = 0;
674 int32_t uid = -1;
675 mAudioAnalytics.mAnalyticsState->timeMachine().get(
676 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
677 if (uid != -1) {
678 std::tie(packageName, versionCode) =
679 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
680 }
681 double playbackPitch = 0.;
682 mAudioAnalytics.mAnalyticsState->timeMachine().get(
683 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
684 double playbackSpeed = 0.;
685 mAudioAnalytics.mAnalyticsState->timeMachine().get(
686 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
687 int32_t selectedDeviceId = 0;
688 mAudioAnalytics.mAnalyticsState->timeMachine().get(
689 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700690 std::string streamType;
691 mAudioAnalytics.mAnalyticsState->timeMachine().get(
692 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700693 std::string traits;
694 mAudioAnalytics.mAnalyticsState->timeMachine().get(
695 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700696 int32_t underrun = 0;
697 mAudioAnalytics.mAnalyticsState->timeMachine().get(
698 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700699 std::string usage;
700 mAudioAnalytics.mAnalyticsState->timeMachine().get(
701 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800702 // Android S
703 std::string logSessionId;
704 mAudioAnalytics.mAnalyticsState->timeMachine().get(
705 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700706
Andy Hung1ea842e2020-05-18 10:47:31 -0700707 const auto callerNameForStats =
708 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
709 const auto contentTypeForStats =
710 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
711 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
712 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
713 const auto streamTypeForStats =
714 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700715 const auto traitsForStats =
716 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700717 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800718 // Android S
719 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700720
Andy Hunga629bd12020-06-05 16:03:53 -0700721 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700722 << " id:" << id
723 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700724 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700725 << " deviceTimeNs:" << deviceTimeNs
726 << " encoding:" << encoding << "(" << encodingForStats
727 << ") frameCount:" << frameCount
728 << " intervalCount:" << intervalCount
729 << " sampleRate:" << sampleRate
730 << " underrun:" << underrun
731 << " flags:" << flags << "(" << flagsForStats
732 << ") callerName:" << callerName << "(" << callerNameForStats
733 << ") contentType:" << contentType << "(" << contentTypeForStats
734 << ") deviceLatencyMs:" << deviceLatencyMs
735 << " deviceStartupMs:" << deviceStartupMs
736 << " deviceVolume:" << deviceVolume
737 << " packageName:" << packageName
738 << " playbackPitch:" << playbackPitch
739 << " playbackSpeed:" << playbackSpeed
740 << " selectedDeviceId:" << selectedDeviceId
741 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700742 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700743 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800744 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700745 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700746 if (clientCalled // only log if client app called AudioTracks
747 && mAudioAnalytics.mDeliverStatistics) {
748 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
749 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700750 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700751 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700752 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700753 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700754 , frameCount
755 , intervalCount
756 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700757 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700758 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700759 , packageName.c_str()
760 , (float)deviceLatencyMs
761 , (float)deviceStartupMs
762 , (float)deviceVolume
763 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700764 , ENUM_EXTRACT(streamTypeForStats)
765 , ENUM_EXTRACT(usageForStats)
766 , ENUM_EXTRACT(contentTypeForStats)
767 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700768 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800769 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700770 );
Andy Hunga629bd12020-06-05 16:03:53 -0700771 ALOGV("%s: statsd %s", __func__, str.c_str());
772 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700773 }
Andy Hungea840382020-05-05 21:50:17 -0700774 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700775 }
776
777 // Report this as needed.
778 if (isBluetooth) {
779 // report this for Bluetooth
780 }
781}
782
783// DeviceConnection helper class.
784void AudioAnalytics::DeviceConnection::a2dpConnected(
785 const std::shared_ptr<const android::mediametrics::Item> &item) {
786 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700787 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700788 {
789 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700790 mA2dpConnectionServiceNs = atNs;
791 ++mA2dpConnectionServices;
792
793 if (mA2dpConnectionRequestNs == 0) {
794 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
795 }
796 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700797 }
798 std::string name;
799 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700800 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
801 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700802}
803
804void AudioAnalytics::DeviceConnection::createPatch(
805 const std::shared_ptr<const android::mediametrics::Item> &item) {
806 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700807 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700808 const std::string& key = item->getKey();
809 std::string outputDevices;
810 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700811 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700812 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700813 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700814 if (mA2dpConnectionRequestNs == 0) {
815 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700816 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700817 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700818 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700819 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700820
Andy Hungea840382020-05-05 21:50:17 -0700821 mA2dpConnectionRequestNs = 0;
822 mA2dpConnectionServiceNs = 0;
823 ++mA2dpConnectionSuccesses;
824
Andy Hung1ea842e2020-05-18 10:47:31 -0700825 const auto connectionTimeMs = float(timeDiffNs * 1e-6);
826
827 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
828 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
829
Andy Hunga629bd12020-06-05 16:03:53 -0700830 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700831 << " A2DP SUCCESS"
832 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700833 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700834 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700835 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700836 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700837
838 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
839 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700840 , ENUM_EXTRACT(inputDeviceBits)
841 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700842 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700843 , types::DEVICE_CONNECTION_RESULT_SUCCESS
844 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700845 , /* connection_count */ 1
846 );
Andy Hunga629bd12020-06-05 16:03:53 -0700847 ALOGV("%s: statsd %s", __func__, str.c_str());
848 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700849 }
Andy Hungce9b6632020-04-28 20:15:17 -0700850 }
851}
852
Andy Hungea840382020-05-05 21:50:17 -0700853// Called through AudioManager when the BT service wants to enable
854void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
855 const std::shared_ptr<const android::mediametrics::Item> &item) {
856 const int64_t atNs = item->getTimestamp();
857 const std::string& key = item->getKey();
858 std::string state;
859 item->get(AMEDIAMETRICS_PROP_STATE, &state);
860 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700861
862 std::string name;
863 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700864 {
865 std::lock_guard l(mLock);
866 mA2dpConnectionRequestNs = atNs;
867 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700868 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700869 }
Andy Hunga629bd12020-06-05 16:03:53 -0700870 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
871 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700872 // TODO: attempt to cancel a timed event, rather than let it expire.
873 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
874}
875
Andy Hungce9b6632020-04-28 20:15:17 -0700876void AudioAnalytics::DeviceConnection::expire() {
877 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700878 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700879
Andy Hung1ea842e2020-05-18 10:47:31 -0700880 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700881 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
882 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
883
Andy Hungea840382020-05-05 21:50:17 -0700884 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700885 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700886
Andy Hunga629bd12020-06-05 16:03:53 -0700887 LOG(LOG_LEVEL) << "A2DP CANCEL"
888 << " outputDevices:" << outputDeviceBits
889 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700890 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700891 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
892 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700893 , ENUM_EXTRACT(inputDeviceBits)
894 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700895 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700896 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700897 , /* connection_time_ms */ 0.f
898 , /* connection_count */ 1
899 );
Andy Hunga629bd12020-06-05 16:03:53 -0700900 ALOGV("%s: statsd %s", __func__, str.c_str());
901 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700902 }
Andy Hungea840382020-05-05 21:50:17 -0700903 return;
904 }
905
906 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
907 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700908 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700909 mA2dpConnectionRequestNs = 0;
910 mA2dpConnectionServiceNs = 0;
911 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700912
Andy Hunga629bd12020-06-05 16:03:53 -0700913 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
914 << " outputDevices:" << outputDeviceBits
915 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700916 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700917 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
918 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700919 , ENUM_EXTRACT(inputDeviceBits)
920 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700921 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700922 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700923 , /* connection_time_ms */ 0.f
924 , /* connection_count */ 1
925 );
Andy Hunga629bd12020-06-05 16:03:53 -0700926 ALOGV("%s: statsd %s", __func__, str.c_str());
927 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700928 }
Andy Hungce9b6632020-04-28 20:15:17 -0700929}
930
jiabin515eb092020-11-18 17:55:52 -0800931void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
932 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
933 const std::string& key = item->getKey();
934
935 std::string callerNameStr;
936 mAudioAnalytics.mAnalyticsState->timeMachine().get(
937 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerNameStr);
938
939 const auto callerName = types::lookup<types::CALLER_NAME, int32_t>(callerNameStr);
940
941 std::string directionStr;
942 mAudioAnalytics.mAnalyticsState->timeMachine().get(
943 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
944 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
945
946 int32_t framesPerBurst = -1;
947 mAudioAnalytics.mAnalyticsState->timeMachine().get(
948 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
949
950 int32_t bufferSizeInFrames = -1;
951 mAudioAnalytics.mAnalyticsState->timeMachine().get(
952 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
953
954 int32_t bufferCapacityInFrames = -1;
955 mAudioAnalytics.mAnalyticsState->timeMachine().get(
956 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
957
958 int32_t channelCount = -1;
959 mAudioAnalytics.mAnalyticsState->timeMachine().get(
960 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
961
962 int64_t totalFramesTransferred = -1;
963 // TODO: log and get total frames transferred
964
965 std::string perfModeRequestedStr;
966 mAudioAnalytics.mAnalyticsState->timeMachine().get(
967 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
968 const auto perfModeRequested =
969 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
970
971 int32_t perfModeActual = 0;
972 // TODO: log and get actual performance mode
973
974 std::string sharingModeStr;
975 mAudioAnalytics.mAnalyticsState->timeMachine().get(
976 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeStr);
977 const auto sharingMode = types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeStr);
978
979 int32_t xrunCount = -1;
980 mAudioAnalytics.mAnalyticsState->timeMachine().get(
981 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
982
jiabin92c9a522021-02-12 22:37:42 +0000983 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -0800984 // TODO: only routed device id is logged, but no device type
985
986 int32_t formatApp = 0;
987 // TODO: log format from app
988
989 std::string formatDeviceStr;
990 mAudioAnalytics.mAnalyticsState->timeMachine().get(
991 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
992 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
993
jiabin92c9a522021-02-12 22:37:42 +0000994 std::string logSessionId;
995 // TODO: log logSessionId
996
jiabin515eb092020-11-18 17:55:52 -0800997 LOG(LOG_LEVEL) << "key:" << key
998 << " caller_name:" << callerName << "(" << callerNameStr << ")"
999 << " path:" << path
1000 << " direction:" << direction << "(" << directionStr << ")"
1001 << " frames_per_burst:" << framesPerBurst
1002 << " buffer_size:" << bufferSizeInFrames
1003 << " buffer_capacity:" << bufferCapacityInFrames
1004 << " channel_count:" << channelCount
1005 << " total_frames_transferred:" << totalFramesTransferred
1006 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
1007 << " perf_mode_actual:" << perfModeActual
1008 << " sharing:" << sharingMode << "(" << sharingModeStr << ")"
1009 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001010 << " device_type:" << serializedDeviceTypes
jiabin515eb092020-11-18 17:55:52 -08001011 << " format_app:" << formatApp
jiabin92c9a522021-02-12 22:37:42 +00001012 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
1013 << " log_session_id: " << logSessionId;
jiabin515eb092020-11-18 17:55:52 -08001014
jiabin92c9a522021-02-12 22:37:42 +00001015 if (mAudioAnalytics.mDeliverStatistics) {
1016 android::util::BytesField bf_serialized(
1017 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1018 const auto result = sendToStatsd(
1019 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
1020 , callerName
1021 , path
1022 , direction
1023 , framesPerBurst
1024 , bufferSizeInFrames
1025 , bufferCapacityInFrames
1026 , channelCount
1027 , totalFramesTransferred
1028 , perfModeRequested
1029 , perfModeActual
1030 , sharingMode
1031 , xrunCount
1032 , bf_serialized
1033 , formatApp
1034 , formatDevice
1035 , logSessionId.c_str()
1036 );
1037 std::stringstream ss;
1038 ss << "result:" << result;
1039 const auto fieldsStr = printFields(AAudioStreamFields,
1040 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
1041 , callerName
1042 , path
1043 , direction
1044 , framesPerBurst
1045 , bufferSizeInFrames
1046 , bufferCapacityInFrames
1047 , channelCount
1048 , totalFramesTransferred
1049 , perfModeRequested
1050 , perfModeActual
1051 , sharingMode
1052 , xrunCount
1053 , serializedDeviceTypes.c_str()
1054 , formatApp
1055 , formatDevice
1056 , logSessionId.c_str()
1057 );
1058 ss << " " << fieldsStr;
1059 std::string str = ss.str();
1060 ALOGV("%s: statsd %s", __func__, str.c_str());
1061 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
1062 }
jiabin515eb092020-11-18 17:55:52 -08001063}
1064
Andy Hung3ab1b322020-05-18 10:47:31 -07001065} // namespace android::mediametrics