blob: 2b797b8951951c51e93500a2b50aabb3c75faadd [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
Andy Hung5be90c82021-03-30 14:30:20 -0700210AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700211 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700212 , mStatsdLog(statsdLog)
213 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800214{
Andy Hunga629bd12020-06-05 16:03:53 -0700215 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800216 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800217
218 // Add action to save AnalyticsState if audioserver is restarted.
219 // This triggers on an item of "audio.flinger"
220 // with a property "event" set to "AudioFlinger" (the constructor).
221 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800222 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
223 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800224 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800225 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
226 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800227 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
228 *mAnalyticsState.get()));
229 // Note: get returns shared_ptr temp, whose lifetime is extended
230 // to end of full expression.
231 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800232 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700233
234 // Set up a timer to expire the previous audio state to save space.
235 // Use the transaction log size as a cookie to see if it is the
236 // same as before. A benign race is possible where a state is cleared early.
237 const size_t size = mPreviousAnalyticsState->transactionLog().size();
238 mTimedAction.postIn(
239 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
240 if (mPreviousAnalyticsState->transactionLog().size() == size) {
241 ALOGD("expiring previous audio state after %d seconds.",
242 PREVIOUS_STATE_EXPIRE_SEC);
243 mPreviousAnalyticsState->clear(); // removes data from the state.
244 }
245 });
Andy Hungea186fa2020-01-09 18:13:15 -0800246 }));
247
jiabin515eb092020-11-18 17:55:52 -0800248 // Handle legacy aaudio stream statistics
249 mActions.addAction(
250 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
251 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
252 std::make_shared<AnalyticsActions::Function>(
253 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
254 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
255 }));
256
257 // Handle mmap aaudio stream statistics
258 mActions.addAction(
259 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
260 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
261 std::make_shared<AnalyticsActions::Function>(
262 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
263 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
264 }));
265
Andy Hungea840382020-05-05 21:50:17 -0700266 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800267 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700268 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
269 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800270 std::make_shared<AnalyticsActions::Function>(
271 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700272 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800273 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700274
275 // Handle device use thread statistics
276 mActions.addAction(
277 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
278 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
279 std::make_shared<AnalyticsActions::Function>(
280 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700281 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700282 }));
283
284 // Handle device use track statistics
285 mActions.addAction(
286 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
287 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
288 std::make_shared<AnalyticsActions::Function>(
289 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700290 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700291 }));
292
Andy Hungea840382020-05-05 21:50:17 -0700293
294 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700295
296 // We track connections (not disconnections) for the time to connect.
297 // TODO: consider BT requests in their A2dp service
298 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
299 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
300 // AudioDeviceBroker.postA2dpActiveDeviceChange
301 mActions.addAction(
302 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700303 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700304 std::make_shared<AnalyticsActions::Function>(
305 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
306 mDeviceConnection.a2dpConnected(item);
307 }));
308 // If audio is active, we expect to see a createAudioPatch after the device is connected.
309 mActions.addAction(
310 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
311 std::string("createAudioPatch"),
312 std::make_shared<AnalyticsActions::Function>(
313 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
314 mDeviceConnection.createPatch(item);
315 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800316
Andy Hungea840382020-05-05 21:50:17 -0700317 // Called from BT service
318 mActions.addAction(
319 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
320 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
321 "." AMEDIAMETRICS_PROP_STATE,
322 "connected",
323 std::make_shared<AnalyticsActions::Function>(
324 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
325 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
326 }));
327
Joey Poomarin52989982020-03-05 17:40:49 +0800328 // Handle power usage
329 mActions.addAction(
330 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
331 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
332 std::make_shared<AnalyticsActions::Function>(
333 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
334 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
335 }));
336
337 mActions.addAction(
338 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
339 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
340 std::make_shared<AnalyticsActions::Function>(
341 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
342 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
343 }));
344
345 mActions.addAction(
346 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
347 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
348 std::make_shared<AnalyticsActions::Function>(
349 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
350 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
351 mAudioPowerUsage.checkMode(item);
352 }));
353
354 mActions.addAction(
355 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
356 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
357 std::make_shared<AnalyticsActions::Function>(
358 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
359 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
360 mAudioPowerUsage.checkVoiceVolume(item);
361 }));
362
363 mActions.addAction(
364 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
365 std::string("createAudioPatch"),
366 std::make_shared<AnalyticsActions::Function>(
367 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
368 mAudioPowerUsage.checkCreatePatch(item);
369 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800370}
371
372AudioAnalytics::~AudioAnalytics()
373{
374 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700375 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800376}
377
378status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800379 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800380{
Andy Hungea186fa2020-01-09 18:13:15 -0800381 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800382 status_t status = mAnalyticsState->submit(item, isTrusted);
383 if (status != NO_ERROR) return status; // may not be permitted.
384
385 // Only if the item was successfully submitted (permission)
386 // do we check triggered actions.
387 checkActions(item);
388 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800389}
390
Andy Hung709b91e2020-04-04 14:23:36 -0700391std::pair<std::string, int32_t> AudioAnalytics::dump(
392 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800393{
394 std::stringstream ss;
395 int32_t ll = lines;
396
397 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700398 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700399 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800400 ll -= l;
401 }
402 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800403 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800404 --ll;
405 }
406 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700407 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700408 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800409 ll -= l;
410 }
Joey Poomarin52989982020-03-05 17:40:49 +0800411
412 if (ll > 0 && prefix == nullptr) {
413 auto [s, l] = mAudioPowerUsage.dump(ll);
414 ss << s;
415 ll -= l;
416 }
Andy Hunga629bd12020-06-05 16:03:53 -0700417
Andy Hung06f3aba2019-12-03 16:36:42 -0800418 return { ss.str(), lines - ll };
419}
420
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800421void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
422{
423 auto actions = mActions.getActionsForItem(item); // internally locked.
424 // Execute actions with no lock held.
425 for (const auto& action : actions) {
426 (*action)(item);
427 }
428}
429
Andy Hungea186fa2020-01-09 18:13:15 -0800430// HELPER METHODS
431
432std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
433{
434 int32_t threadId_int32{};
435 if (mAnalyticsState->timeMachine().get(
436 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
437 return {};
438 }
439 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
440}
441
Andy Hungce9b6632020-04-28 20:15:17 -0700442// DeviceUse helper class.
443void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700444 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700445 const std::string& key = item->getKey();
446 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700447 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
448 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
449 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700450 - 1);
451 // deliver statistics
452 int64_t deviceTimeNs = 0;
453 mAudioAnalytics.mAnalyticsState->timeMachine().get(
454 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
455 std::string encoding;
456 mAudioAnalytics.mAnalyticsState->timeMachine().get(
457 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
458 int32_t frameCount = 0;
459 mAudioAnalytics.mAnalyticsState->timeMachine().get(
460 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700461 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700462 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700463 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700464 int32_t intervalCount = 0;
465 mAudioAnalytics.mAnalyticsState->timeMachine().get(
466 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700467 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700468 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700469 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700470 int32_t sampleRate = 0;
471 mAudioAnalytics.mAnalyticsState->timeMachine().get(
472 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700473 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700474 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700475 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700476
Andy Hungea840382020-05-05 21:50:17 -0700477 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700478 // Accumulate the bit flags for input and output devices.
479 std::stringstream oss;
480 long_enum_type_t outputDeviceBits{};
481 { // compute outputDevices
482 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700483 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700484 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
485 oss << device;
486 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700487 }
488 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700489 const std::string outputDevices = oss.str();
490
491 std::stringstream iss;
492 long_enum_type_t inputDeviceBits{};
493 { // compute inputDevices
494 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
495 for (const auto& [device, addr] : devaddrvec) {
496 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
497 iss << device;
498 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
499 }
500 }
501 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700502
503 // Get connected device name if from bluetooth.
504 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700505
506 std::string inputDeviceNames; // not filled currently.
507 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700508 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
509 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700510 outputDeviceNames = SUPPRESSED;
511#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700512 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700513 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700514 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700515 stringutils::replace(outputDeviceNames, "|", '?');
516 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
517 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
518 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700519#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700520 }
521
Andy Hungea840382020-05-05 21:50:17 -0700522 switch (itemType) {
523 case RECORD: {
524 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700525 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
526 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700527
Andy Hungea840382020-05-05 21:50:17 -0700528 std::string packageName;
529 int64_t versionCode = 0;
530 int32_t uid = -1;
531 mAudioAnalytics.mAnalyticsState->timeMachine().get(
532 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
533 if (uid != -1) {
534 std::tie(packageName, versionCode) =
535 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
536 }
537
538 int32_t selectedDeviceId = 0;
539 mAudioAnalytics.mAnalyticsState->timeMachine().get(
540 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
541 std::string source;
542 mAudioAnalytics.mAnalyticsState->timeMachine().get(
543 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800544 // Android S
545 std::string logSessionId;
546 mAudioAnalytics.mAnalyticsState->timeMachine().get(
547 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700548
Andy Hung1ea842e2020-05-18 10:47:31 -0700549 const auto callerNameForStats =
550 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
551 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
552 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
553 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800554 // Android S
555 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700556
Andy Hunga629bd12020-06-05 16:03:53 -0700557 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700558 << " id:" << id
559 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700560 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700561 << " deviceTimeNs:" << deviceTimeNs
562 << " encoding:" << encoding << "(" << encodingForStats
563 << ") frameCount:" << frameCount
564 << " intervalCount:" << intervalCount
565 << " sampleRate:" << sampleRate
566 << " flags:" << flags << "(" << flagsForStats
567 << ") packageName:" << packageName
568 << " selectedDeviceId:" << selectedDeviceId
569 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800570 << ") source:" << source << "(" << sourceForStats
571 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
572 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700573 if (clientCalled // only log if client app called AudioRecord.
574 && mAudioAnalytics.mDeliverStatistics) {
575 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
576 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700577 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700578 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700579 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700580 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700581 , frameCount
582 , intervalCount
583 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700584 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700585
586 , packageName.c_str()
587 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700588 , ENUM_EXTRACT(callerNameForStats)
589 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800590 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700591 );
Andy Hunga629bd12020-06-05 16:03:53 -0700592 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700593 mAudioAnalytics.mStatsdLog->log(
594 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700595 }
Andy Hungea840382020-05-05 21:50:17 -0700596 } break;
597 case THREAD: {
598 std::string type;
599 mAudioAnalytics.mAnalyticsState->timeMachine().get(
600 key, AMEDIAMETRICS_PROP_TYPE, &type);
601 int32_t underrun = 0; // zero for record types
602 mAudioAnalytics.mAnalyticsState->timeMachine().get(
603 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700604
605 const bool isInput = types::isInputThreadType(type);
606 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
607 const auto flagsForStats =
608 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
609 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
610 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
611
Andy Hunga629bd12020-06-05 16:03:53 -0700612 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700613 << " id:" << id
614 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
615 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700616 << ") inputDeviceNames:" << inputDeviceNames
617 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700618 << " deviceTimeNs:" << deviceTimeNs
619 << " encoding:" << encoding << "(" << encodingForStats
620 << ") frameCount:" << frameCount
621 << " intervalCount:" << intervalCount
622 << " sampleRate:" << sampleRate
623 << " underrun:" << underrun
624 << " flags:" << flags << "(" << flagsForStats
625 << ") type:" << type << "(" << typeForStats
626 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700627 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700628 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
629 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
630 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
631 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700632 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700633 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700634 , frameCount
635 , intervalCount
636 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700637 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700638 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700639 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700640 );
Andy Hunga629bd12020-06-05 16:03:53 -0700641 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700642 mAudioAnalytics.mStatsdLog->log(
643 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700644 }
Andy Hungea840382020-05-05 21:50:17 -0700645 } break;
646 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700647 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700648 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
649 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
650
Andy Hungce9b6632020-04-28 20:15:17 -0700651 std::string contentType;
652 mAudioAnalytics.mAnalyticsState->timeMachine().get(
653 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
654 double deviceLatencyMs = 0.;
655 mAudioAnalytics.mAnalyticsState->timeMachine().get(
656 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
657 double deviceStartupMs = 0.;
658 mAudioAnalytics.mAnalyticsState->timeMachine().get(
659 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
660 double deviceVolume = 0.;
661 mAudioAnalytics.mAnalyticsState->timeMachine().get(
662 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
663 std::string packageName;
664 int64_t versionCode = 0;
665 int32_t uid = -1;
666 mAudioAnalytics.mAnalyticsState->timeMachine().get(
667 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
668 if (uid != -1) {
669 std::tie(packageName, versionCode) =
670 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
671 }
672 double playbackPitch = 0.;
673 mAudioAnalytics.mAnalyticsState->timeMachine().get(
674 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
675 double playbackSpeed = 0.;
676 mAudioAnalytics.mAnalyticsState->timeMachine().get(
677 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
678 int32_t selectedDeviceId = 0;
679 mAudioAnalytics.mAnalyticsState->timeMachine().get(
680 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700681 std::string streamType;
682 mAudioAnalytics.mAnalyticsState->timeMachine().get(
683 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700684 std::string traits;
685 mAudioAnalytics.mAnalyticsState->timeMachine().get(
686 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700687 int32_t underrun = 0;
688 mAudioAnalytics.mAnalyticsState->timeMachine().get(
689 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700690 std::string usage;
691 mAudioAnalytics.mAnalyticsState->timeMachine().get(
692 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800693 // Android S
694 std::string logSessionId;
695 mAudioAnalytics.mAnalyticsState->timeMachine().get(
696 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700697
Andy Hung1ea842e2020-05-18 10:47:31 -0700698 const auto callerNameForStats =
699 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
700 const auto contentTypeForStats =
701 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
702 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
703 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
704 const auto streamTypeForStats =
705 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700706 const auto traitsForStats =
707 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700708 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800709 // Android S
710 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700711
Andy Hunga629bd12020-06-05 16:03:53 -0700712 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700713 << " id:" << id
714 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700715 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700716 << " deviceTimeNs:" << deviceTimeNs
717 << " encoding:" << encoding << "(" << encodingForStats
718 << ") frameCount:" << frameCount
719 << " intervalCount:" << intervalCount
720 << " sampleRate:" << sampleRate
721 << " underrun:" << underrun
722 << " flags:" << flags << "(" << flagsForStats
723 << ") callerName:" << callerName << "(" << callerNameForStats
724 << ") contentType:" << contentType << "(" << contentTypeForStats
725 << ") deviceLatencyMs:" << deviceLatencyMs
726 << " deviceStartupMs:" << deviceStartupMs
727 << " deviceVolume:" << deviceVolume
728 << " packageName:" << packageName
729 << " playbackPitch:" << playbackPitch
730 << " playbackSpeed:" << playbackSpeed
731 << " selectedDeviceId:" << selectedDeviceId
732 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700733 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700734 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800735 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700736 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700737 if (clientCalled // only log if client app called AudioTracks
738 && mAudioAnalytics.mDeliverStatistics) {
739 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
740 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700741 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700742 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700743 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700744 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700745 , frameCount
746 , intervalCount
747 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700748 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700749 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700750 , packageName.c_str()
751 , (float)deviceLatencyMs
752 , (float)deviceStartupMs
753 , (float)deviceVolume
754 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700755 , ENUM_EXTRACT(streamTypeForStats)
756 , ENUM_EXTRACT(usageForStats)
757 , ENUM_EXTRACT(contentTypeForStats)
758 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700759 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800760 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700761 );
Andy Hunga629bd12020-06-05 16:03:53 -0700762 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700763 mAudioAnalytics.mStatsdLog->log(
764 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -0700765 }
Andy Hungea840382020-05-05 21:50:17 -0700766 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700767 }
768
769 // Report this as needed.
770 if (isBluetooth) {
771 // report this for Bluetooth
772 }
773}
774
775// DeviceConnection helper class.
776void AudioAnalytics::DeviceConnection::a2dpConnected(
777 const std::shared_ptr<const android::mediametrics::Item> &item) {
778 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700779 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700780 {
781 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700782 mA2dpConnectionServiceNs = atNs;
783 ++mA2dpConnectionServices;
784
785 if (mA2dpConnectionRequestNs == 0) {
786 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
787 }
788 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700789 }
790 std::string name;
791 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700792 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
793 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700794}
795
796void AudioAnalytics::DeviceConnection::createPatch(
797 const std::shared_ptr<const android::mediametrics::Item> &item) {
798 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700799 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700800 const std::string& key = item->getKey();
801 std::string outputDevices;
802 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700803 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700804 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700805 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700806 if (mA2dpConnectionRequestNs == 0) {
807 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700808 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700809 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700810 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700811 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700812
Andy Hungea840382020-05-05 21:50:17 -0700813 mA2dpConnectionRequestNs = 0;
814 mA2dpConnectionServiceNs = 0;
815 ++mA2dpConnectionSuccesses;
816
Andy Hungc14ee142021-03-10 16:39:02 -0800817 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -0700818
819 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
820 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
821
Andy Hunga629bd12020-06-05 16:03:53 -0700822 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700823 << " A2DP SUCCESS"
824 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700825 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700826 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700827 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700828 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700829
830 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
831 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700832 , ENUM_EXTRACT(inputDeviceBits)
833 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700834 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700835 , types::DEVICE_CONNECTION_RESULT_SUCCESS
836 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700837 , /* connection_count */ 1
838 );
Andy Hunga629bd12020-06-05 16:03:53 -0700839 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700840 mAudioAnalytics.mStatsdLog->log(
841 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700842 }
Andy Hungce9b6632020-04-28 20:15:17 -0700843 }
844}
845
Andy Hungea840382020-05-05 21:50:17 -0700846// Called through AudioManager when the BT service wants to enable
847void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
848 const std::shared_ptr<const android::mediametrics::Item> &item) {
849 const int64_t atNs = item->getTimestamp();
850 const std::string& key = item->getKey();
851 std::string state;
852 item->get(AMEDIAMETRICS_PROP_STATE, &state);
853 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700854
855 std::string name;
856 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700857 {
858 std::lock_guard l(mLock);
859 mA2dpConnectionRequestNs = atNs;
860 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700861 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700862 }
Andy Hunga629bd12020-06-05 16:03:53 -0700863 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
864 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700865 // TODO: attempt to cancel a timed event, rather than let it expire.
866 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
867}
868
Andy Hungce9b6632020-04-28 20:15:17 -0700869void AudioAnalytics::DeviceConnection::expire() {
870 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700871 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700872
Andy Hung1ea842e2020-05-18 10:47:31 -0700873 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700874 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
875 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
876
Andy Hungea840382020-05-05 21:50:17 -0700877 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700878 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700879
Andy Hunga629bd12020-06-05 16:03:53 -0700880 LOG(LOG_LEVEL) << "A2DP CANCEL"
881 << " outputDevices:" << outputDeviceBits
882 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700883 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700884 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
885 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700886 , ENUM_EXTRACT(inputDeviceBits)
887 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700888 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700889 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700890 , /* connection_time_ms */ 0.f
891 , /* connection_count */ 1
892 );
Andy Hunga629bd12020-06-05 16:03:53 -0700893 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700894 mAudioAnalytics.mStatsdLog->log(
895 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700896 }
Andy Hungea840382020-05-05 21:50:17 -0700897 return;
898 }
899
900 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
901 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700902 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700903 mA2dpConnectionRequestNs = 0;
904 mA2dpConnectionServiceNs = 0;
905 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700906
Andy Hunga629bd12020-06-05 16:03:53 -0700907 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
908 << " outputDevices:" << outputDeviceBits
909 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700910 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700911 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
912 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700913 , ENUM_EXTRACT(inputDeviceBits)
914 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700915 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700916 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700917 , /* connection_time_ms */ 0.f
918 , /* connection_count */ 1
919 );
Andy Hunga629bd12020-06-05 16:03:53 -0700920 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700921 mAudioAnalytics.mStatsdLog->log(
922 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700923 }
Andy Hungce9b6632020-04-28 20:15:17 -0700924}
925
jiabin515eb092020-11-18 17:55:52 -0800926void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
927 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
928 const std::string& key = item->getKey();
929
jiabin515eb092020-11-18 17:55:52 -0800930 std::string directionStr;
931 mAudioAnalytics.mAnalyticsState->timeMachine().get(
932 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
933 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
934
935 int32_t framesPerBurst = -1;
936 mAudioAnalytics.mAnalyticsState->timeMachine().get(
937 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
938
939 int32_t bufferSizeInFrames = -1;
940 mAudioAnalytics.mAnalyticsState->timeMachine().get(
941 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
942
943 int32_t bufferCapacityInFrames = -1;
944 mAudioAnalytics.mAnalyticsState->timeMachine().get(
945 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
946
947 int32_t channelCount = -1;
948 mAudioAnalytics.mAnalyticsState->timeMachine().get(
949 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
950
951 int64_t totalFramesTransferred = -1;
952 // TODO: log and get total frames transferred
953
954 std::string perfModeRequestedStr;
955 mAudioAnalytics.mAnalyticsState->timeMachine().get(
956 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
957 const auto perfModeRequested =
958 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
959
960 int32_t perfModeActual = 0;
961 // TODO: log and get actual performance mode
962
963 std::string sharingModeStr;
964 mAudioAnalytics.mAnalyticsState->timeMachine().get(
965 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeStr);
966 const auto sharingMode = types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeStr);
967
968 int32_t xrunCount = -1;
969 mAudioAnalytics.mAnalyticsState->timeMachine().get(
970 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
971
jiabin92c9a522021-02-12 22:37:42 +0000972 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -0800973 // TODO: only routed device id is logged, but no device type
974
975 int32_t formatApp = 0;
976 // TODO: log format from app
977
978 std::string formatDeviceStr;
979 mAudioAnalytics.mAnalyticsState->timeMachine().get(
980 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
981 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
982
jiabin92c9a522021-02-12 22:37:42 +0000983 std::string logSessionId;
984 // TODO: log logSessionId
985
jiabinc4c331c2021-03-23 17:11:01 +0000986 int32_t sampleRate = 0;
987 mAudioAnalytics.mAnalyticsState->timeMachine().get(
988 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
989
990 std::string contentTypeStr;
991 mAudioAnalytics.mAnalyticsState->timeMachine().get(
992 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
993 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
994
jiabin515eb092020-11-18 17:55:52 -0800995 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -0800996 << " path:" << path
997 << " direction:" << direction << "(" << directionStr << ")"
998 << " frames_per_burst:" << framesPerBurst
999 << " buffer_size:" << bufferSizeInFrames
1000 << " buffer_capacity:" << bufferCapacityInFrames
1001 << " channel_count:" << channelCount
1002 << " total_frames_transferred:" << totalFramesTransferred
1003 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
1004 << " perf_mode_actual:" << perfModeActual
1005 << " sharing:" << sharingMode << "(" << sharingModeStr << ")"
1006 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001007 << " device_type:" << serializedDeviceTypes
jiabin515eb092020-11-18 17:55:52 -08001008 << " format_app:" << formatApp
jiabin92c9a522021-02-12 22:37:42 +00001009 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001010 << " log_session_id: " << logSessionId
1011 << " sample_rate: " << sampleRate
1012 << " content_type: " << contentType << "(" << contentTypeStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001013
jiabin92c9a522021-02-12 22:37:42 +00001014 if (mAudioAnalytics.mDeliverStatistics) {
1015 android::util::BytesField bf_serialized(
1016 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1017 const auto result = sendToStatsd(
1018 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001019 , path
1020 , direction
1021 , framesPerBurst
1022 , bufferSizeInFrames
1023 , bufferCapacityInFrames
1024 , channelCount
1025 , totalFramesTransferred
1026 , perfModeRequested
1027 , perfModeActual
1028 , sharingMode
1029 , xrunCount
1030 , bf_serialized
1031 , formatApp
1032 , formatDevice
1033 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001034 , sampleRate
1035 , contentType
jiabin92c9a522021-02-12 22:37:42 +00001036 );
1037 std::stringstream ss;
1038 ss << "result:" << result;
1039 const auto fieldsStr = printFields(AAudioStreamFields,
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 , serializedDeviceTypes.c_str()
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 ss << " " << fieldsStr;
1060 std::string str = ss.str();
1061 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001062 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001063 }
jiabin515eb092020-11-18 17:55:52 -08001064}
1065
Andy Hung3ab1b322020-05-18 10:47:31 -07001066} // namespace android::mediametrics