blob: 3b2de7699c3bbc9a66b996728efe6c548ee4399a [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",
90};
91
92static constexpr const char * const AudioThreadDeviceUsageFields[] = {
93 "mediametrics_audiothreaddeviceusage_reported",
94 "devices",
95 "device_names",
96 "device_time_nanos",
97 "encoding",
98 "frame_count",
99 "interval_count",
100 "sample_rate",
101 "flags",
102 "xruns",
103 "type",
104};
105
106static constexpr const char * const AudioTrackDeviceUsageFields[] = {
107 "mediametrics_audiotrackdeviceusage_reported",
108 "devices",
109 "device_names",
110 "device_time_nanos",
111 "encoding",
112 "frame_count",
113 "interval_count",
114 "sample_rate",
115 "flags",
116 "xruns",
117 "package_name",
118 "device_latency_millis",
119 "device_startup_millis",
120 "device_volume",
121 "selected_device_id",
122 "stream_type",
123 "usage",
124 "content_type",
125 "caller",
126 "traits",
127};
128
129static constexpr const char * const AudioDeviceConnectionFields[] = {
130 "mediametrics_audiodeviceconnection_reported",
131 "input_devices",
132 "output_devices",
133 "device_names",
134 "result",
135 "time_to_connect_millis",
136 "connection_count",
137};
138
jiabin515eb092020-11-18 17:55:52 -0800139// static constexpr const char * const AAudioStreamFields[] {
140// "mediametrics_aaudiostream_reported",
141// "caller_name",
142// "path",
143// "direction",
144// "frames_per_burst",
145// "buffer_size",
146// "buffer_capacity",
147// "channel_count",
148// "total_frames_transferred",
149// "perf_mode_requested",
150// "perf_mode_actual",
151// "sharing",
152// "xrun_count",
153// "device_type",
154// "format_app",
155// "format_device",
156// };
157
Andy Hunga629bd12020-06-05 16:03:53 -0700158/**
159 * sendToStatsd is a helper method that sends the arguments to statsd
160 * and returns a pair { result, summary_string }.
161 */
162template <size_t N, typename ...Types>
163std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
164{
165 int result = 0;
166 std::stringstream ss;
167
168#ifdef STATSD_ENABLE
169 result = android::util::stats_write(args...);
170 ss << "result:" << result;
171#endif
172 ss << " { ";
173 stringutils::fieldPrint(ss, fields, args...);
174 ss << "}";
175 return { result, ss.str() };
176}
Andy Hung06f3aba2019-12-03 16:36:42 -0800177
178AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -0700179 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -0800180{
Andy Hunga629bd12020-06-05 16:03:53 -0700181 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800182 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800183
184 // Add action to save AnalyticsState if audioserver is restarted.
185 // This triggers on an item of "audio.flinger"
186 // with a property "event" set to "AudioFlinger" (the constructor).
187 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800188 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
189 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800190 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800191 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
192 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800193 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
194 *mAnalyticsState.get()));
195 // Note: get returns shared_ptr temp, whose lifetime is extended
196 // to end of full expression.
197 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800198 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700199
200 // Set up a timer to expire the previous audio state to save space.
201 // Use the transaction log size as a cookie to see if it is the
202 // same as before. A benign race is possible where a state is cleared early.
203 const size_t size = mPreviousAnalyticsState->transactionLog().size();
204 mTimedAction.postIn(
205 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
206 if (mPreviousAnalyticsState->transactionLog().size() == size) {
207 ALOGD("expiring previous audio state after %d seconds.",
208 PREVIOUS_STATE_EXPIRE_SEC);
209 mPreviousAnalyticsState->clear(); // removes data from the state.
210 }
211 });
Andy Hungea186fa2020-01-09 18:13:15 -0800212 }));
213
jiabin515eb092020-11-18 17:55:52 -0800214 // Handle legacy aaudio stream statistics
215 mActions.addAction(
216 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
217 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
218 std::make_shared<AnalyticsActions::Function>(
219 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
220 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
221 }));
222
223 // Handle mmap aaudio stream statistics
224 mActions.addAction(
225 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
226 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
227 std::make_shared<AnalyticsActions::Function>(
228 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
229 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
230 }));
231
Andy Hungea840382020-05-05 21:50:17 -0700232 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800233 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700234 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
235 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800236 std::make_shared<AnalyticsActions::Function>(
237 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700238 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800239 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700240
241 // Handle device use thread statistics
242 mActions.addAction(
243 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
244 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
245 std::make_shared<AnalyticsActions::Function>(
246 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700247 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700248 }));
249
250 // Handle device use track statistics
251 mActions.addAction(
252 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
253 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
254 std::make_shared<AnalyticsActions::Function>(
255 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700256 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700257 }));
258
Andy Hungea840382020-05-05 21:50:17 -0700259
260 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700261
262 // We track connections (not disconnections) for the time to connect.
263 // TODO: consider BT requests in their A2dp service
264 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
265 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
266 // AudioDeviceBroker.postA2dpActiveDeviceChange
267 mActions.addAction(
268 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700269 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700270 std::make_shared<AnalyticsActions::Function>(
271 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
272 mDeviceConnection.a2dpConnected(item);
273 }));
274 // If audio is active, we expect to see a createAudioPatch after the device is connected.
275 mActions.addAction(
276 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
277 std::string("createAudioPatch"),
278 std::make_shared<AnalyticsActions::Function>(
279 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
280 mDeviceConnection.createPatch(item);
281 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800282
Andy Hungea840382020-05-05 21:50:17 -0700283 // Called from BT service
284 mActions.addAction(
285 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
286 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
287 "." AMEDIAMETRICS_PROP_STATE,
288 "connected",
289 std::make_shared<AnalyticsActions::Function>(
290 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
291 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
292 }));
293
Joey Poomarin52989982020-03-05 17:40:49 +0800294 // Handle power usage
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){
300 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
301 }));
302
303 mActions.addAction(
304 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
305 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
306 std::make_shared<AnalyticsActions::Function>(
307 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
308 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
309 }));
310
311 mActions.addAction(
312 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
313 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
314 std::make_shared<AnalyticsActions::Function>(
315 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
316 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
317 mAudioPowerUsage.checkMode(item);
318 }));
319
320 mActions.addAction(
321 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
322 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
323 std::make_shared<AnalyticsActions::Function>(
324 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
325 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
326 mAudioPowerUsage.checkVoiceVolume(item);
327 }));
328
329 mActions.addAction(
330 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
331 std::string("createAudioPatch"),
332 std::make_shared<AnalyticsActions::Function>(
333 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
334 mAudioPowerUsage.checkCreatePatch(item);
335 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800336}
337
338AudioAnalytics::~AudioAnalytics()
339{
340 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700341 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800342}
343
344status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800345 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800346{
Andy Hungea186fa2020-01-09 18:13:15 -0800347 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800348 status_t status = mAnalyticsState->submit(item, isTrusted);
349 if (status != NO_ERROR) return status; // may not be permitted.
350
351 // Only if the item was successfully submitted (permission)
352 // do we check triggered actions.
353 checkActions(item);
354 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800355}
356
Andy Hung709b91e2020-04-04 14:23:36 -0700357std::pair<std::string, int32_t> AudioAnalytics::dump(
358 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800359{
360 std::stringstream ss;
361 int32_t ll = lines;
362
363 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700364 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700365 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800366 ll -= l;
367 }
368 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800369 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800370 --ll;
371 }
372 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700373 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700374 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800375 ll -= l;
376 }
Joey Poomarin52989982020-03-05 17:40:49 +0800377
Andy Hunga629bd12020-06-05 16:03:53 -0700378 if (ll > 0) {
379 // Print the statsd atoms we sent out.
380 const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
381 const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
382 if ((size_t)ll >= n) {
383 if (n == 1) {
384 ss << "Statsd atoms: empty or truncated\n";
385 } else {
386 ss << "Statsd atoms:\n" << statsd;
387 }
388 ll -= n;
389 }
390 }
391
Joey Poomarin52989982020-03-05 17:40:49 +0800392 if (ll > 0 && prefix == nullptr) {
393 auto [s, l] = mAudioPowerUsage.dump(ll);
394 ss << s;
395 ll -= l;
396 }
Andy Hunga629bd12020-06-05 16:03:53 -0700397
Andy Hung06f3aba2019-12-03 16:36:42 -0800398 return { ss.str(), lines - ll };
399}
400
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800401void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
402{
403 auto actions = mActions.getActionsForItem(item); // internally locked.
404 // Execute actions with no lock held.
405 for (const auto& action : actions) {
406 (*action)(item);
407 }
408}
409
Andy Hungea186fa2020-01-09 18:13:15 -0800410// HELPER METHODS
411
412std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
413{
414 int32_t threadId_int32{};
415 if (mAnalyticsState->timeMachine().get(
416 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
417 return {};
418 }
419 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
420}
421
Andy Hungce9b6632020-04-28 20:15:17 -0700422// DeviceUse helper class.
423void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700424 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700425 const std::string& key = item->getKey();
426 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700427 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
428 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
429 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700430 - 1);
431 // deliver statistics
432 int64_t deviceTimeNs = 0;
433 mAudioAnalytics.mAnalyticsState->timeMachine().get(
434 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
435 std::string encoding;
436 mAudioAnalytics.mAnalyticsState->timeMachine().get(
437 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
438 int32_t frameCount = 0;
439 mAudioAnalytics.mAnalyticsState->timeMachine().get(
440 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700441 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700442 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700443 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700444 int32_t intervalCount = 0;
445 mAudioAnalytics.mAnalyticsState->timeMachine().get(
446 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700447 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700448 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700449 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700450 int32_t sampleRate = 0;
451 mAudioAnalytics.mAnalyticsState->timeMachine().get(
452 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700453 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700454 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700455 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700456
Andy Hungea840382020-05-05 21:50:17 -0700457 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700458 // Accumulate the bit flags for input and output devices.
459 std::stringstream oss;
460 long_enum_type_t outputDeviceBits{};
461 { // compute outputDevices
462 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700463 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700464 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
465 oss << device;
466 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700467 }
468 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700469 const std::string outputDevices = oss.str();
470
471 std::stringstream iss;
472 long_enum_type_t inputDeviceBits{};
473 { // compute inputDevices
474 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
475 for (const auto& [device, addr] : devaddrvec) {
476 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
477 iss << device;
478 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
479 }
480 }
481 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700482
483 // Get connected device name if from bluetooth.
484 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700485
486 std::string inputDeviceNames; // not filled currently.
487 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700488 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
489 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700490 outputDeviceNames = SUPPRESSED;
491#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700492 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700493 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700494 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700495 stringutils::replace(outputDeviceNames, "|", '?');
496 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
497 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
498 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700499#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700500 }
501
Andy Hungea840382020-05-05 21:50:17 -0700502 switch (itemType) {
503 case RECORD: {
504 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700505 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
506 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700507
Andy Hungea840382020-05-05 21:50:17 -0700508 std::string packageName;
509 int64_t versionCode = 0;
510 int32_t uid = -1;
511 mAudioAnalytics.mAnalyticsState->timeMachine().get(
512 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
513 if (uid != -1) {
514 std::tie(packageName, versionCode) =
515 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
516 }
517
518 int32_t selectedDeviceId = 0;
519 mAudioAnalytics.mAnalyticsState->timeMachine().get(
520 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
521 std::string source;
522 mAudioAnalytics.mAnalyticsState->timeMachine().get(
523 key, AMEDIAMETRICS_PROP_SOURCE, &source);
524
Andy Hung1ea842e2020-05-18 10:47:31 -0700525 const auto callerNameForStats =
526 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
527 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
528 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
529 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungea840382020-05-05 21:50:17 -0700530
Andy Hunga629bd12020-06-05 16:03:53 -0700531 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700532 << " id:" << id
533 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700534 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700535 << " deviceTimeNs:" << deviceTimeNs
536 << " encoding:" << encoding << "(" << encodingForStats
537 << ") frameCount:" << frameCount
538 << " intervalCount:" << intervalCount
539 << " sampleRate:" << sampleRate
540 << " flags:" << flags << "(" << flagsForStats
541 << ") packageName:" << packageName
542 << " selectedDeviceId:" << selectedDeviceId
543 << " callerName:" << callerName << "(" << callerNameForStats
544 << ") source:" << source << "(" << sourceForStats << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700545 if (clientCalled // only log if client app called AudioRecord.
546 && mAudioAnalytics.mDeliverStatistics) {
547 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
548 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700549 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700550 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700551 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700552 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700553 , frameCount
554 , intervalCount
555 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700556 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700557
558 , packageName.c_str()
559 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700560 , ENUM_EXTRACT(callerNameForStats)
561 , ENUM_EXTRACT(sourceForStats)
Andy Hungea840382020-05-05 21:50:17 -0700562 );
Andy Hunga629bd12020-06-05 16:03:53 -0700563 ALOGV("%s: statsd %s", __func__, str.c_str());
564 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700565 }
Andy Hungea840382020-05-05 21:50:17 -0700566 } break;
567 case THREAD: {
568 std::string type;
569 mAudioAnalytics.mAnalyticsState->timeMachine().get(
570 key, AMEDIAMETRICS_PROP_TYPE, &type);
571 int32_t underrun = 0; // zero for record types
572 mAudioAnalytics.mAnalyticsState->timeMachine().get(
573 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700574
575 const bool isInput = types::isInputThreadType(type);
576 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
577 const auto flagsForStats =
578 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
579 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
580 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
581
Andy Hunga629bd12020-06-05 16:03:53 -0700582 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700583 << " id:" << id
584 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
585 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700586 << ") inputDeviceNames:" << inputDeviceNames
587 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700588 << " deviceTimeNs:" << deviceTimeNs
589 << " encoding:" << encoding << "(" << encodingForStats
590 << ") frameCount:" << frameCount
591 << " intervalCount:" << intervalCount
592 << " sampleRate:" << sampleRate
593 << " underrun:" << underrun
594 << " flags:" << flags << "(" << flagsForStats
595 << ") type:" << type << "(" << typeForStats
596 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700597 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700598 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
599 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
600 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
601 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700602 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700603 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700604 , frameCount
605 , intervalCount
606 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700607 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700608 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700609 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700610 );
Andy Hunga629bd12020-06-05 16:03:53 -0700611 ALOGV("%s: statsd %s", __func__, str.c_str());
612 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700613 }
Andy Hungea840382020-05-05 21:50:17 -0700614 } break;
615 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700616 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700617 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
618 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
619
Andy Hungce9b6632020-04-28 20:15:17 -0700620 std::string contentType;
621 mAudioAnalytics.mAnalyticsState->timeMachine().get(
622 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
623 double deviceLatencyMs = 0.;
624 mAudioAnalytics.mAnalyticsState->timeMachine().get(
625 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
626 double deviceStartupMs = 0.;
627 mAudioAnalytics.mAnalyticsState->timeMachine().get(
628 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
629 double deviceVolume = 0.;
630 mAudioAnalytics.mAnalyticsState->timeMachine().get(
631 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
632 std::string packageName;
633 int64_t versionCode = 0;
634 int32_t uid = -1;
635 mAudioAnalytics.mAnalyticsState->timeMachine().get(
636 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
637 if (uid != -1) {
638 std::tie(packageName, versionCode) =
639 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
640 }
641 double playbackPitch = 0.;
642 mAudioAnalytics.mAnalyticsState->timeMachine().get(
643 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
644 double playbackSpeed = 0.;
645 mAudioAnalytics.mAnalyticsState->timeMachine().get(
646 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
647 int32_t selectedDeviceId = 0;
648 mAudioAnalytics.mAnalyticsState->timeMachine().get(
649 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700650 std::string streamType;
651 mAudioAnalytics.mAnalyticsState->timeMachine().get(
652 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700653 std::string traits;
654 mAudioAnalytics.mAnalyticsState->timeMachine().get(
655 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700656 int32_t underrun = 0;
657 mAudioAnalytics.mAnalyticsState->timeMachine().get(
658 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700659 std::string usage;
660 mAudioAnalytics.mAnalyticsState->timeMachine().get(
661 key, AMEDIAMETRICS_PROP_USAGE, &usage);
662
Andy Hung1ea842e2020-05-18 10:47:31 -0700663 const auto callerNameForStats =
664 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
665 const auto contentTypeForStats =
666 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
667 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
668 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
669 const auto streamTypeForStats =
670 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700671 const auto traitsForStats =
672 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700673 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
674
Andy Hunga629bd12020-06-05 16:03:53 -0700675 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700676 << " id:" << id
677 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700678 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700679 << " deviceTimeNs:" << deviceTimeNs
680 << " encoding:" << encoding << "(" << encodingForStats
681 << ") frameCount:" << frameCount
682 << " intervalCount:" << intervalCount
683 << " sampleRate:" << sampleRate
684 << " underrun:" << underrun
685 << " flags:" << flags << "(" << flagsForStats
686 << ") callerName:" << callerName << "(" << callerNameForStats
687 << ") contentType:" << contentType << "(" << contentTypeForStats
688 << ") deviceLatencyMs:" << deviceLatencyMs
689 << " deviceStartupMs:" << deviceStartupMs
690 << " deviceVolume:" << deviceVolume
691 << " packageName:" << packageName
692 << " playbackPitch:" << playbackPitch
693 << " playbackSpeed:" << playbackSpeed
694 << " selectedDeviceId:" << selectedDeviceId
695 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700696 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700697 << ") usage:" << usage << "(" << usageForStats
698 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700699 if (clientCalled // only log if client app called AudioTracks
700 && mAudioAnalytics.mDeliverStatistics) {
701 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
702 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700703 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700704 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700705 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700706 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700707 , frameCount
708 , intervalCount
709 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700710 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700711 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700712 , packageName.c_str()
713 , (float)deviceLatencyMs
714 , (float)deviceStartupMs
715 , (float)deviceVolume
716 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700717 , ENUM_EXTRACT(streamTypeForStats)
718 , ENUM_EXTRACT(usageForStats)
719 , ENUM_EXTRACT(contentTypeForStats)
720 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700721 , ENUM_EXTRACT(traitsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700722 );
Andy Hunga629bd12020-06-05 16:03:53 -0700723 ALOGV("%s: statsd %s", __func__, str.c_str());
724 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700725 }
Andy Hungea840382020-05-05 21:50:17 -0700726 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700727 }
728
729 // Report this as needed.
730 if (isBluetooth) {
731 // report this for Bluetooth
732 }
733}
734
735// DeviceConnection helper class.
736void AudioAnalytics::DeviceConnection::a2dpConnected(
737 const std::shared_ptr<const android::mediametrics::Item> &item) {
738 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700739 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700740 {
741 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700742 mA2dpConnectionServiceNs = atNs;
743 ++mA2dpConnectionServices;
744
745 if (mA2dpConnectionRequestNs == 0) {
746 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
747 }
748 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700749 }
750 std::string name;
751 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700752 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
753 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700754}
755
756void AudioAnalytics::DeviceConnection::createPatch(
757 const std::shared_ptr<const android::mediametrics::Item> &item) {
758 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700759 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700760 const std::string& key = item->getKey();
761 std::string outputDevices;
762 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700763 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700764 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700765 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700766 if (mA2dpConnectionRequestNs == 0) {
767 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700768 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700769 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700770 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700771 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700772
Andy Hungea840382020-05-05 21:50:17 -0700773 mA2dpConnectionRequestNs = 0;
774 mA2dpConnectionServiceNs = 0;
775 ++mA2dpConnectionSuccesses;
776
Andy Hung1ea842e2020-05-18 10:47:31 -0700777 const auto connectionTimeMs = float(timeDiffNs * 1e-6);
778
779 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
780 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
781
Andy Hunga629bd12020-06-05 16:03:53 -0700782 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700783 << " A2DP SUCCESS"
784 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700785 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700786 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700787 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700788 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700789
790 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
791 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700792 , ENUM_EXTRACT(inputDeviceBits)
793 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700794 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700795 , types::DEVICE_CONNECTION_RESULT_SUCCESS
796 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700797 , /* connection_count */ 1
798 );
Andy Hunga629bd12020-06-05 16:03:53 -0700799 ALOGV("%s: statsd %s", __func__, str.c_str());
800 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700801 }
Andy Hungce9b6632020-04-28 20:15:17 -0700802 }
803}
804
Andy Hungea840382020-05-05 21:50:17 -0700805// Called through AudioManager when the BT service wants to enable
806void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
807 const std::shared_ptr<const android::mediametrics::Item> &item) {
808 const int64_t atNs = item->getTimestamp();
809 const std::string& key = item->getKey();
810 std::string state;
811 item->get(AMEDIAMETRICS_PROP_STATE, &state);
812 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700813
814 std::string name;
815 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700816 {
817 std::lock_guard l(mLock);
818 mA2dpConnectionRequestNs = atNs;
819 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700820 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700821 }
Andy Hunga629bd12020-06-05 16:03:53 -0700822 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
823 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700824 // TODO: attempt to cancel a timed event, rather than let it expire.
825 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
826}
827
Andy Hungce9b6632020-04-28 20:15:17 -0700828void AudioAnalytics::DeviceConnection::expire() {
829 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700830 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700831
Andy Hung1ea842e2020-05-18 10:47:31 -0700832 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700833 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
834 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
835
Andy Hungea840382020-05-05 21:50:17 -0700836 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700837 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700838
Andy Hunga629bd12020-06-05 16:03:53 -0700839 LOG(LOG_LEVEL) << "A2DP CANCEL"
840 << " outputDevices:" << outputDeviceBits
841 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700842 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700843 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
844 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700845 , ENUM_EXTRACT(inputDeviceBits)
846 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700847 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700848 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700849 , /* connection_time_ms */ 0.f
850 , /* connection_count */ 1
851 );
Andy Hunga629bd12020-06-05 16:03:53 -0700852 ALOGV("%s: statsd %s", __func__, str.c_str());
853 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700854 }
Andy Hungea840382020-05-05 21:50:17 -0700855 return;
856 }
857
858 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
859 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700860 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700861 mA2dpConnectionRequestNs = 0;
862 mA2dpConnectionServiceNs = 0;
863 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700864
Andy Hunga629bd12020-06-05 16:03:53 -0700865 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
866 << " outputDevices:" << outputDeviceBits
867 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700868 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700869 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
870 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700871 , ENUM_EXTRACT(inputDeviceBits)
872 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700873 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700874 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700875 , /* connection_time_ms */ 0.f
876 , /* connection_count */ 1
877 );
Andy Hunga629bd12020-06-05 16:03:53 -0700878 ALOGV("%s: statsd %s", __func__, str.c_str());
879 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700880 }
Andy Hungce9b6632020-04-28 20:15:17 -0700881}
882
jiabin515eb092020-11-18 17:55:52 -0800883void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
884 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
885 const std::string& key = item->getKey();
886
887 std::string callerNameStr;
888 mAudioAnalytics.mAnalyticsState->timeMachine().get(
889 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerNameStr);
890
891 const auto callerName = types::lookup<types::CALLER_NAME, int32_t>(callerNameStr);
892
893 std::string directionStr;
894 mAudioAnalytics.mAnalyticsState->timeMachine().get(
895 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
896 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
897
898 int32_t framesPerBurst = -1;
899 mAudioAnalytics.mAnalyticsState->timeMachine().get(
900 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
901
902 int32_t bufferSizeInFrames = -1;
903 mAudioAnalytics.mAnalyticsState->timeMachine().get(
904 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
905
906 int32_t bufferCapacityInFrames = -1;
907 mAudioAnalytics.mAnalyticsState->timeMachine().get(
908 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
909
910 int32_t channelCount = -1;
911 mAudioAnalytics.mAnalyticsState->timeMachine().get(
912 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
913
914 int64_t totalFramesTransferred = -1;
915 // TODO: log and get total frames transferred
916
917 std::string perfModeRequestedStr;
918 mAudioAnalytics.mAnalyticsState->timeMachine().get(
919 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
920 const auto perfModeRequested =
921 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
922
923 int32_t perfModeActual = 0;
924 // TODO: log and get actual performance mode
925
926 std::string sharingModeStr;
927 mAudioAnalytics.mAnalyticsState->timeMachine().get(
928 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeStr);
929 const auto sharingMode = types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeStr);
930
931 int32_t xrunCount = -1;
932 mAudioAnalytics.mAnalyticsState->timeMachine().get(
933 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
934
935 std::string deviceType;
936 // TODO: only routed device id is logged, but no device type
937
938 int32_t formatApp = 0;
939 // TODO: log format from app
940
941 std::string formatDeviceStr;
942 mAudioAnalytics.mAnalyticsState->timeMachine().get(
943 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
944 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
945
946 LOG(LOG_LEVEL) << "key:" << key
947 << " caller_name:" << callerName << "(" << callerNameStr << ")"
948 << " path:" << path
949 << " direction:" << direction << "(" << directionStr << ")"
950 << " frames_per_burst:" << framesPerBurst
951 << " buffer_size:" << bufferSizeInFrames
952 << " buffer_capacity:" << bufferCapacityInFrames
953 << " channel_count:" << channelCount
954 << " total_frames_transferred:" << totalFramesTransferred
955 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
956 << " perf_mode_actual:" << perfModeActual
957 << " sharing:" << sharingMode << "(" << sharingModeStr << ")"
958 << " xrun_count:" << xrunCount
959 << " device_type:" << deviceType
960 << " format_app:" << formatApp
961 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")";
962
963 // TODO: send the metric to statsd when the proto is ready
964 // if (mAudioAnalytics.mDeliverStatistics) {
965 // const auto [ result, str ] = sendToStatsd(AAudioStreamFields,
966 // CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
967 // , callerName
968 // , path
969 // , direction
970 // , framesPerBurst
971 // , bufferSizeInFrames
972 // , bufferCapacityInFrames
973 // , channelCount
974 // , totalFramesTransferred
975 // , perfModeRequested
976 // , perfModeActual
977 // , sharingMode
978 // , xrunCount
979 // , deviceType.c_str()
980 // , formatApp
981 // , formatDevice
982 // );
983 // ALOGV("%s: statsd %s", __func__, str.c_str());
984 // mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
985 // }
986}
987
Andy Hung3ab1b322020-05-18 10:47:31 -0700988} // namespace android::mediametrics