blob: 11ec9932550fbdf2d2020c8a3565a1dccf578da8 [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",
jiabinc8da9032021-04-28 20:42:36 +0000160 "sharing_requested",
jiabin92c9a522021-02-12 22:37:42 +0000161};
162
163/**
164 * printFields is a helper method that prints the fields and corresponding values
165 * in a human readable style.
166 */
167template <size_t N, typename ...Types>
168std::string printFields(const char * const (& fields)[N], Types ... args)
169{
170 std::stringstream ss;
171 ss << " { ";
172 stringutils::fieldPrint(ss, fields, args...);
173 ss << "}";
174 return ss.str();
175}
176
177/**
178 * sendToStatsd is a helper method that sends the arguments to statsd
179 */
180template <typename ...Types>
181int sendToStatsd(Types ... args)
182{
183 int result = 0;
184
185#ifdef STATSD_ENABLE
186 result = android::util::stats_write(args...);
187#endif
188 return result;
189}
jiabin515eb092020-11-18 17:55:52 -0800190
Andy Hunga629bd12020-06-05 16:03:53 -0700191/**
192 * sendToStatsd is a helper method that sends the arguments to statsd
193 * and returns a pair { result, summary_string }.
194 */
195template <size_t N, typename ...Types>
196std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
197{
198 int result = 0;
199 std::stringstream ss;
200
201#ifdef STATSD_ENABLE
202 result = android::util::stats_write(args...);
203 ss << "result:" << result;
204#endif
205 ss << " { ";
206 stringutils::fieldPrint(ss, fields, args...);
207 ss << "}";
208 return { result, ss.str() };
209}
Andy Hung06f3aba2019-12-03 16:36:42 -0800210
Andy Hung5be90c82021-03-30 14:30:20 -0700211AudioAnalytics::AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog)
Andy Hung1ea842e2020-05-18 10:47:31 -0700212 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung5be90c82021-03-30 14:30:20 -0700213 , mStatsdLog(statsdLog)
214 , mAudioPowerUsage(this, statsdLog)
Andy Hung06f3aba2019-12-03 16:36:42 -0800215{
Andy Hunga629bd12020-06-05 16:03:53 -0700216 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800217 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800218
219 // Add action to save AnalyticsState if audioserver is restarted.
220 // This triggers on an item of "audio.flinger"
221 // with a property "event" set to "AudioFlinger" (the constructor).
222 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800223 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
224 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800225 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800226 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
227 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800228 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
229 *mAnalyticsState.get()));
230 // Note: get returns shared_ptr temp, whose lifetime is extended
231 // to end of full expression.
232 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800233 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700234
235 // Set up a timer to expire the previous audio state to save space.
236 // Use the transaction log size as a cookie to see if it is the
237 // same as before. A benign race is possible where a state is cleared early.
238 const size_t size = mPreviousAnalyticsState->transactionLog().size();
239 mTimedAction.postIn(
240 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
241 if (mPreviousAnalyticsState->transactionLog().size() == size) {
242 ALOGD("expiring previous audio state after %d seconds.",
243 PREVIOUS_STATE_EXPIRE_SEC);
244 mPreviousAnalyticsState->clear(); // removes data from the state.
245 }
246 });
Andy Hungea186fa2020-01-09 18:13:15 -0800247 }));
248
jiabin97247ea2021-04-07 00:33:38 +0000249 // Handle legacy aaudio playback stream statistics
jiabin515eb092020-11-18 17:55:52 -0800250 mActions.addAction(
251 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
252 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
253 std::make_shared<AnalyticsActions::Function>(
254 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
255 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
256 }));
257
jiabin97247ea2021-04-07 00:33:38 +0000258 // Handle legacy aaudio capture stream statistics
259 mActions.addAction(
260 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
261 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
262 std::make_shared<AnalyticsActions::Function>(
263 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
264 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
265 }));
266
jiabin515eb092020-11-18 17:55:52 -0800267 // Handle mmap aaudio stream statistics
268 mActions.addAction(
269 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
270 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
271 std::make_shared<AnalyticsActions::Function>(
272 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
273 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
274 }));
275
Andy Hungea840382020-05-05 21:50:17 -0700276 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800277 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700278 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
279 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800280 std::make_shared<AnalyticsActions::Function>(
281 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700282 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800283 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700284
285 // Handle device use thread statistics
286 mActions.addAction(
287 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
288 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
289 std::make_shared<AnalyticsActions::Function>(
290 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700291 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700292 }));
293
294 // Handle device use track statistics
295 mActions.addAction(
296 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
297 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
298 std::make_shared<AnalyticsActions::Function>(
299 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700300 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700301 }));
302
Andy Hungea840382020-05-05 21:50:17 -0700303
304 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700305
306 // We track connections (not disconnections) for the time to connect.
307 // TODO: consider BT requests in their A2dp service
308 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
309 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
310 // AudioDeviceBroker.postA2dpActiveDeviceChange
311 mActions.addAction(
312 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700313 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700314 std::make_shared<AnalyticsActions::Function>(
315 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
316 mDeviceConnection.a2dpConnected(item);
317 }));
318 // If audio is active, we expect to see a createAudioPatch after the device is connected.
319 mActions.addAction(
320 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
321 std::string("createAudioPatch"),
322 std::make_shared<AnalyticsActions::Function>(
323 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
324 mDeviceConnection.createPatch(item);
325 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800326
Andy Hungea840382020-05-05 21:50:17 -0700327 // Called from BT service
328 mActions.addAction(
329 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
330 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
331 "." AMEDIAMETRICS_PROP_STATE,
332 "connected",
333 std::make_shared<AnalyticsActions::Function>(
334 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
335 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
336 }));
337
Joey Poomarin52989982020-03-05 17:40:49 +0800338 // Handle power usage
339 mActions.addAction(
340 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
341 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
342 std::make_shared<AnalyticsActions::Function>(
343 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
344 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
345 }));
346
347 mActions.addAction(
348 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
349 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
350 std::make_shared<AnalyticsActions::Function>(
351 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
352 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
353 }));
354
355 mActions.addAction(
356 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
357 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
358 std::make_shared<AnalyticsActions::Function>(
359 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
360 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
361 mAudioPowerUsage.checkMode(item);
362 }));
363
364 mActions.addAction(
365 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
366 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
367 std::make_shared<AnalyticsActions::Function>(
368 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
369 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
370 mAudioPowerUsage.checkVoiceVolume(item);
371 }));
372
373 mActions.addAction(
374 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
375 std::string("createAudioPatch"),
376 std::make_shared<AnalyticsActions::Function>(
377 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
378 mAudioPowerUsage.checkCreatePatch(item);
379 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800380}
381
382AudioAnalytics::~AudioAnalytics()
383{
384 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700385 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800386}
387
388status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800389 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800390{
Andy Hungea186fa2020-01-09 18:13:15 -0800391 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800392 status_t status = mAnalyticsState->submit(item, isTrusted);
393 if (status != NO_ERROR) return status; // may not be permitted.
394
395 // Only if the item was successfully submitted (permission)
396 // do we check triggered actions.
397 checkActions(item);
398 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800399}
400
Andy Hung709b91e2020-04-04 14:23:36 -0700401std::pair<std::string, int32_t> AudioAnalytics::dump(
402 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800403{
404 std::stringstream ss;
405 int32_t ll = lines;
406
407 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700408 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700409 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800410 ll -= l;
411 }
412 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800413 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800414 --ll;
415 }
416 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700417 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700418 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800419 ll -= l;
420 }
Joey Poomarin52989982020-03-05 17:40:49 +0800421
422 if (ll > 0 && prefix == nullptr) {
423 auto [s, l] = mAudioPowerUsage.dump(ll);
424 ss << s;
425 ll -= l;
426 }
Andy Hunga629bd12020-06-05 16:03:53 -0700427
Andy Hung06f3aba2019-12-03 16:36:42 -0800428 return { ss.str(), lines - ll };
429}
430
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800431void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
432{
433 auto actions = mActions.getActionsForItem(item); // internally locked.
434 // Execute actions with no lock held.
435 for (const auto& action : actions) {
436 (*action)(item);
437 }
438}
439
Andy Hungea186fa2020-01-09 18:13:15 -0800440// HELPER METHODS
441
442std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
443{
444 int32_t threadId_int32{};
445 if (mAnalyticsState->timeMachine().get(
446 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
447 return {};
448 }
449 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
450}
451
Andy Hungce9b6632020-04-28 20:15:17 -0700452// DeviceUse helper class.
453void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700454 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700455 const std::string& key = item->getKey();
456 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700457 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
458 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
459 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700460 - 1);
461 // deliver statistics
462 int64_t deviceTimeNs = 0;
463 mAudioAnalytics.mAnalyticsState->timeMachine().get(
464 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
465 std::string encoding;
466 mAudioAnalytics.mAnalyticsState->timeMachine().get(
467 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
468 int32_t frameCount = 0;
469 mAudioAnalytics.mAnalyticsState->timeMachine().get(
470 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700471 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700472 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700473 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700474 int32_t intervalCount = 0;
475 mAudioAnalytics.mAnalyticsState->timeMachine().get(
476 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700477 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700478 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700479 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700480 int32_t sampleRate = 0;
481 mAudioAnalytics.mAnalyticsState->timeMachine().get(
482 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700483 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700484 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700485 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700486
Andy Hungea840382020-05-05 21:50:17 -0700487 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700488 // Accumulate the bit flags for input and output devices.
489 std::stringstream oss;
490 long_enum_type_t outputDeviceBits{};
491 { // compute outputDevices
492 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700493 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700494 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
495 oss << device;
496 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700497 }
498 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700499 const std::string outputDevices = oss.str();
500
501 std::stringstream iss;
502 long_enum_type_t inputDeviceBits{};
503 { // compute inputDevices
504 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
505 for (const auto& [device, addr] : devaddrvec) {
506 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
507 iss << device;
508 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
509 }
510 }
511 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700512
513 // Get connected device name if from bluetooth.
514 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700515
516 std::string inputDeviceNames; // not filled currently.
517 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700518 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
519 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700520 outputDeviceNames = SUPPRESSED;
521#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700522 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700523 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700524 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700525 stringutils::replace(outputDeviceNames, "|", '?');
526 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
527 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
528 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700529#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700530 }
531
Andy Hungea840382020-05-05 21:50:17 -0700532 switch (itemType) {
533 case RECORD: {
534 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700535 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
536 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700537
Andy Hungea840382020-05-05 21:50:17 -0700538 std::string packageName;
539 int64_t versionCode = 0;
540 int32_t uid = -1;
541 mAudioAnalytics.mAnalyticsState->timeMachine().get(
542 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
543 if (uid != -1) {
544 std::tie(packageName, versionCode) =
545 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
546 }
547
548 int32_t selectedDeviceId = 0;
549 mAudioAnalytics.mAnalyticsState->timeMachine().get(
550 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
551 std::string source;
552 mAudioAnalytics.mAnalyticsState->timeMachine().get(
553 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800554 // Android S
555 std::string logSessionId;
556 mAudioAnalytics.mAnalyticsState->timeMachine().get(
557 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700558
Andy Hung1ea842e2020-05-18 10:47:31 -0700559 const auto callerNameForStats =
560 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
561 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
562 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
563 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800564 // Android S
565 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700566
Andy Hunga629bd12020-06-05 16:03:53 -0700567 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700568 << " id:" << id
569 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700570 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700571 << " deviceTimeNs:" << deviceTimeNs
572 << " encoding:" << encoding << "(" << encodingForStats
573 << ") frameCount:" << frameCount
574 << " intervalCount:" << intervalCount
575 << " sampleRate:" << sampleRate
576 << " flags:" << flags << "(" << flagsForStats
577 << ") packageName:" << packageName
578 << " selectedDeviceId:" << selectedDeviceId
579 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800580 << ") source:" << source << "(" << sourceForStats
581 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
582 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700583 if (clientCalled // only log if client app called AudioRecord.
584 && mAudioAnalytics.mDeliverStatistics) {
585 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
586 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700587 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700588 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700589 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700590 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700591 , frameCount
592 , intervalCount
593 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700594 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700595
596 , packageName.c_str()
597 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700598 , ENUM_EXTRACT(callerNameForStats)
599 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800600 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700601 );
Andy Hunga629bd12020-06-05 16:03:53 -0700602 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700603 mAudioAnalytics.mStatsdLog->log(
604 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED, 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());
Andy Hung5be90c82021-03-30 14:30:20 -0700652 mAudioAnalytics.mStatsdLog->log(
653 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700654 }
Andy Hungea840382020-05-05 21:50:17 -0700655 } break;
656 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700657 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700658 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
659 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
660
Andy Hungce9b6632020-04-28 20:15:17 -0700661 std::string contentType;
662 mAudioAnalytics.mAnalyticsState->timeMachine().get(
663 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
664 double deviceLatencyMs = 0.;
665 mAudioAnalytics.mAnalyticsState->timeMachine().get(
666 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
667 double deviceStartupMs = 0.;
668 mAudioAnalytics.mAnalyticsState->timeMachine().get(
669 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
670 double deviceVolume = 0.;
671 mAudioAnalytics.mAnalyticsState->timeMachine().get(
672 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
673 std::string packageName;
674 int64_t versionCode = 0;
675 int32_t uid = -1;
676 mAudioAnalytics.mAnalyticsState->timeMachine().get(
677 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
678 if (uid != -1) {
679 std::tie(packageName, versionCode) =
680 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
681 }
682 double playbackPitch = 0.;
683 mAudioAnalytics.mAnalyticsState->timeMachine().get(
684 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
685 double playbackSpeed = 0.;
686 mAudioAnalytics.mAnalyticsState->timeMachine().get(
687 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
688 int32_t selectedDeviceId = 0;
689 mAudioAnalytics.mAnalyticsState->timeMachine().get(
690 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700691 std::string streamType;
692 mAudioAnalytics.mAnalyticsState->timeMachine().get(
693 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700694 std::string traits;
695 mAudioAnalytics.mAnalyticsState->timeMachine().get(
696 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700697 int32_t underrun = 0;
698 mAudioAnalytics.mAnalyticsState->timeMachine().get(
699 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700700 std::string usage;
701 mAudioAnalytics.mAnalyticsState->timeMachine().get(
702 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800703 // Android S
704 std::string logSessionId;
705 mAudioAnalytics.mAnalyticsState->timeMachine().get(
706 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700707
Andy Hung1ea842e2020-05-18 10:47:31 -0700708 const auto callerNameForStats =
709 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
710 const auto contentTypeForStats =
711 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
712 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
713 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
714 const auto streamTypeForStats =
715 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700716 const auto traitsForStats =
717 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700718 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800719 // Android S
720 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700721
Andy Hunga629bd12020-06-05 16:03:53 -0700722 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700723 << " id:" << id
724 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700725 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700726 << " deviceTimeNs:" << deviceTimeNs
727 << " encoding:" << encoding << "(" << encodingForStats
728 << ") frameCount:" << frameCount
729 << " intervalCount:" << intervalCount
730 << " sampleRate:" << sampleRate
731 << " underrun:" << underrun
732 << " flags:" << flags << "(" << flagsForStats
733 << ") callerName:" << callerName << "(" << callerNameForStats
734 << ") contentType:" << contentType << "(" << contentTypeForStats
735 << ") deviceLatencyMs:" << deviceLatencyMs
736 << " deviceStartupMs:" << deviceStartupMs
737 << " deviceVolume:" << deviceVolume
738 << " packageName:" << packageName
739 << " playbackPitch:" << playbackPitch
740 << " playbackSpeed:" << playbackSpeed
741 << " selectedDeviceId:" << selectedDeviceId
742 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700743 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700744 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800745 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700746 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700747 if (clientCalled // only log if client app called AudioTracks
748 && mAudioAnalytics.mDeliverStatistics) {
749 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
750 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700751 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700752 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700753 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700754 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700755 , frameCount
756 , intervalCount
757 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700758 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700759 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700760 , packageName.c_str()
761 , (float)deviceLatencyMs
762 , (float)deviceStartupMs
763 , (float)deviceVolume
764 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700765 , ENUM_EXTRACT(streamTypeForStats)
766 , ENUM_EXTRACT(usageForStats)
767 , ENUM_EXTRACT(contentTypeForStats)
768 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700769 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800770 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700771 );
Andy Hunga629bd12020-06-05 16:03:53 -0700772 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700773 mAudioAnalytics.mStatsdLog->log(
774 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED, str);
Andy Hungce9b6632020-04-28 20:15:17 -0700775 }
Andy Hungea840382020-05-05 21:50:17 -0700776 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700777 }
778
779 // Report this as needed.
780 if (isBluetooth) {
781 // report this for Bluetooth
782 }
783}
784
785// DeviceConnection helper class.
786void AudioAnalytics::DeviceConnection::a2dpConnected(
787 const std::shared_ptr<const android::mediametrics::Item> &item) {
788 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700789 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700790 {
791 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700792 mA2dpConnectionServiceNs = atNs;
793 ++mA2dpConnectionServices;
794
795 if (mA2dpConnectionRequestNs == 0) {
796 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
797 }
798 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700799 }
800 std::string name;
801 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700802 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
803 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700804}
805
806void AudioAnalytics::DeviceConnection::createPatch(
807 const std::shared_ptr<const android::mediametrics::Item> &item) {
808 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700809 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700810 const std::string& key = item->getKey();
811 std::string outputDevices;
812 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700813 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700814 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700815 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700816 if (mA2dpConnectionRequestNs == 0) {
817 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700818 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700819 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700820 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700821 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700822
Andy Hungea840382020-05-05 21:50:17 -0700823 mA2dpConnectionRequestNs = 0;
824 mA2dpConnectionServiceNs = 0;
825 ++mA2dpConnectionSuccesses;
826
Andy Hungc14ee142021-03-10 16:39:02 -0800827 const auto connectionTimeMs = float((double)timeDiffNs * 1e-6);
Andy Hung1ea842e2020-05-18 10:47:31 -0700828
829 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
830 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
831
Andy Hunga629bd12020-06-05 16:03:53 -0700832 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700833 << " A2DP SUCCESS"
834 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700835 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700836 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700837 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700838 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700839
840 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
841 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700842 , ENUM_EXTRACT(inputDeviceBits)
843 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700844 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700845 , types::DEVICE_CONNECTION_RESULT_SUCCESS
846 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700847 , /* connection_count */ 1
848 );
Andy Hunga629bd12020-06-05 16:03:53 -0700849 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700850 mAudioAnalytics.mStatsdLog->log(
851 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700852 }
Andy Hungce9b6632020-04-28 20:15:17 -0700853 }
854}
855
Andy Hungea840382020-05-05 21:50:17 -0700856// Called through AudioManager when the BT service wants to enable
857void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
858 const std::shared_ptr<const android::mediametrics::Item> &item) {
859 const int64_t atNs = item->getTimestamp();
860 const std::string& key = item->getKey();
861 std::string state;
862 item->get(AMEDIAMETRICS_PROP_STATE, &state);
863 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700864
865 std::string name;
866 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700867 {
868 std::lock_guard l(mLock);
869 mA2dpConnectionRequestNs = atNs;
870 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700871 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700872 }
Andy Hunga629bd12020-06-05 16:03:53 -0700873 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
874 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700875 // TODO: attempt to cancel a timed event, rather than let it expire.
876 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
877}
878
Andy Hungce9b6632020-04-28 20:15:17 -0700879void AudioAnalytics::DeviceConnection::expire() {
880 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700881 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700882
Andy Hung1ea842e2020-05-18 10:47:31 -0700883 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700884 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
885 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
886
Andy Hungea840382020-05-05 21:50:17 -0700887 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700888 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700889
Andy Hunga629bd12020-06-05 16:03:53 -0700890 LOG(LOG_LEVEL) << "A2DP CANCEL"
891 << " outputDevices:" << outputDeviceBits
892 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700893 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700894 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
895 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700896 , ENUM_EXTRACT(inputDeviceBits)
897 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700898 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700899 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700900 , /* connection_time_ms */ 0.f
901 , /* connection_count */ 1
902 );
Andy Hunga629bd12020-06-05 16:03:53 -0700903 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700904 mAudioAnalytics.mStatsdLog->log(
905 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700906 }
Andy Hungea840382020-05-05 21:50:17 -0700907 return;
908 }
909
910 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
911 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700912 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700913 mA2dpConnectionRequestNs = 0;
914 mA2dpConnectionServiceNs = 0;
915 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700916
Andy Hunga629bd12020-06-05 16:03:53 -0700917 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
918 << " outputDevices:" << outputDeviceBits
919 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700920 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700921 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
922 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700923 , ENUM_EXTRACT(inputDeviceBits)
924 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700925 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700926 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700927 , /* connection_time_ms */ 0.f
928 , /* connection_count */ 1
929 );
Andy Hunga629bd12020-06-05 16:03:53 -0700930 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -0700931 mAudioAnalytics.mStatsdLog->log(
932 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED, str);
Andy Hungea840382020-05-05 21:50:17 -0700933 }
Andy Hungce9b6632020-04-28 20:15:17 -0700934}
935
jiabin515eb092020-11-18 17:55:52 -0800936void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
937 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
938 const std::string& key = item->getKey();
939
jiabin515eb092020-11-18 17:55:52 -0800940 std::string directionStr;
941 mAudioAnalytics.mAnalyticsState->timeMachine().get(
942 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
943 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
944
945 int32_t framesPerBurst = -1;
946 mAudioAnalytics.mAnalyticsState->timeMachine().get(
947 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
948
949 int32_t bufferSizeInFrames = -1;
950 mAudioAnalytics.mAnalyticsState->timeMachine().get(
951 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
952
953 int32_t bufferCapacityInFrames = -1;
954 mAudioAnalytics.mAnalyticsState->timeMachine().get(
955 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
956
957 int32_t channelCount = -1;
958 mAudioAnalytics.mAnalyticsState->timeMachine().get(
959 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
960
961 int64_t totalFramesTransferred = -1;
jiabin97247ea2021-04-07 00:33:38 +0000962 mAudioAnalytics.mAnalyticsState->timeMachine().get(
963 key, AMEDIAMETRICS_PROP_FRAMESTRANSFERRED, &totalFramesTransferred);
jiabin515eb092020-11-18 17:55:52 -0800964
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
jiabin97247ea2021-04-07 00:33:38 +0000971 std::string perfModeActualStr;
972 mAudioAnalytics.mAnalyticsState->timeMachine().get(
973 key, AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL, &perfModeActualStr);
974 const auto perfModeActual =
975 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeActualStr);
jiabin515eb092020-11-18 17:55:52 -0800976
jiabinc8da9032021-04-28 20:42:36 +0000977 std::string sharingModeActualStr;
jiabin515eb092020-11-18 17:55:52 -0800978 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinc8da9032021-04-28 20:42:36 +0000979 key, AMEDIAMETRICS_PROP_SHARINGMODEACTUAL, &sharingModeActualStr);
980 const auto sharingModeActual =
981 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeActualStr);
jiabin515eb092020-11-18 17:55:52 -0800982
983 int32_t xrunCount = -1;
984 mAudioAnalytics.mAnalyticsState->timeMachine().get(
985 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
986
jiabin92c9a522021-02-12 22:37:42 +0000987 std::string serializedDeviceTypes;
jiabin515eb092020-11-18 17:55:52 -0800988 // TODO: only routed device id is logged, but no device type
989
jiabin97247ea2021-04-07 00:33:38 +0000990 std::string formatAppStr;
991 mAudioAnalytics.mAnalyticsState->timeMachine().get(
jiabinef348b82021-04-19 16:53:08 +0000992 key, AMEDIAMETRICS_PROP_ENCODINGCLIENT, &formatAppStr);
jiabin97247ea2021-04-07 00:33:38 +0000993 const auto formatApp = types::lookup<types::ENCODING, int32_t>(formatAppStr);
jiabin515eb092020-11-18 17:55:52 -0800994
995 std::string formatDeviceStr;
996 mAudioAnalytics.mAnalyticsState->timeMachine().get(
997 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
998 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
999
jiabin92c9a522021-02-12 22:37:42 +00001000 std::string logSessionId;
jiabin97247ea2021-04-07 00:33:38 +00001001 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1002 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
jiabin92c9a522021-02-12 22:37:42 +00001003
jiabinc4c331c2021-03-23 17:11:01 +00001004 int32_t sampleRate = 0;
1005 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1006 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
1007
1008 std::string contentTypeStr;
1009 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1010 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentTypeStr);
1011 const auto contentType = types::lookup<types::CONTENT_TYPE, int32_t>(contentTypeStr);
1012
jiabinc8da9032021-04-28 20:42:36 +00001013 std::string sharingModeRequestedStr;
1014 mAudioAnalytics.mAnalyticsState->timeMachine().get(
1015 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeRequestedStr);
1016 const auto sharingModeRequested =
1017 types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
1018
jiabin515eb092020-11-18 17:55:52 -08001019 LOG(LOG_LEVEL) << "key:" << key
jiabin515eb092020-11-18 17:55:52 -08001020 << " path:" << path
1021 << " direction:" << direction << "(" << directionStr << ")"
1022 << " frames_per_burst:" << framesPerBurst
1023 << " buffer_size:" << bufferSizeInFrames
1024 << " buffer_capacity:" << bufferCapacityInFrames
1025 << " channel_count:" << channelCount
1026 << " total_frames_transferred:" << totalFramesTransferred
1027 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
jiabin97247ea2021-04-07 00:33:38 +00001028 << " perf_mode_actual:" << perfModeActual << "(" << perfModeActualStr << ")"
jiabinc8da9032021-04-28 20:42:36 +00001029 << " sharing:" << sharingModeActual << "(" << sharingModeActualStr << ")"
jiabin515eb092020-11-18 17:55:52 -08001030 << " xrun_count:" << xrunCount
jiabin92c9a522021-02-12 22:37:42 +00001031 << " device_type:" << serializedDeviceTypes
jiabin97247ea2021-04-07 00:33:38 +00001032 << " format_app:" << formatApp << "(" << formatAppStr << ")"
jiabin92c9a522021-02-12 22:37:42 +00001033 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")"
jiabinc4c331c2021-03-23 17:11:01 +00001034 << " log_session_id: " << logSessionId
1035 << " sample_rate: " << sampleRate
jiabinc8da9032021-04-28 20:42:36 +00001036 << " content_type: " << contentType << "(" << contentTypeStr << ")"
1037 << " sharing_requested:" << sharingModeRequested
1038 << "(" << sharingModeRequestedStr << ")";
jiabin515eb092020-11-18 17:55:52 -08001039
jiabin92c9a522021-02-12 22:37:42 +00001040 if (mAudioAnalytics.mDeliverStatistics) {
1041 android::util::BytesField bf_serialized(
1042 serializedDeviceTypes.c_str(), serializedDeviceTypes.size());
1043 const auto result = sendToStatsd(
1044 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001045 , path
1046 , direction
1047 , framesPerBurst
1048 , bufferSizeInFrames
1049 , bufferCapacityInFrames
1050 , channelCount
1051 , totalFramesTransferred
1052 , perfModeRequested
1053 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001054 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001055 , xrunCount
1056 , bf_serialized
1057 , formatApp
1058 , formatDevice
1059 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001060 , sampleRate
1061 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001062 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001063 );
1064 std::stringstream ss;
1065 ss << "result:" << result;
1066 const auto fieldsStr = printFields(AAudioStreamFields,
1067 CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
jiabin92c9a522021-02-12 22:37:42 +00001068 , path
1069 , direction
1070 , framesPerBurst
1071 , bufferSizeInFrames
1072 , bufferCapacityInFrames
1073 , channelCount
1074 , totalFramesTransferred
1075 , perfModeRequested
1076 , perfModeActual
jiabinc8da9032021-04-28 20:42:36 +00001077 , sharingModeActual
jiabin92c9a522021-02-12 22:37:42 +00001078 , xrunCount
1079 , serializedDeviceTypes.c_str()
1080 , formatApp
1081 , formatDevice
1082 , logSessionId.c_str()
jiabinc4c331c2021-03-23 17:11:01 +00001083 , sampleRate
1084 , contentType
jiabinc8da9032021-04-28 20:42:36 +00001085 , sharingModeRequested
jiabin92c9a522021-02-12 22:37:42 +00001086 );
1087 ss << " " << fieldsStr;
1088 std::string str = ss.str();
1089 ALOGV("%s: statsd %s", __func__, str.c_str());
Andy Hung5be90c82021-03-30 14:30:20 -07001090 mAudioAnalytics.mStatsdLog->log(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED, str);
jiabin92c9a522021-02-12 22:37:42 +00001091 }
jiabin515eb092020-11-18 17:55:52 -08001092}
1093
Andy Hung3ab1b322020-05-18 10:47:31 -07001094} // namespace android::mediametrics