blob: 9b7da0f50a2da58a3cef53ff3b8a251218173a7e [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
jiabin515eb092020-11-18 17:55:52 -0800141// static constexpr const char * const AAudioStreamFields[] {
142// "mediametrics_aaudiostream_reported",
143// "caller_name",
144// "path",
145// "direction",
146// "frames_per_burst",
147// "buffer_size",
148// "buffer_capacity",
149// "channel_count",
150// "total_frames_transferred",
151// "perf_mode_requested",
152// "perf_mode_actual",
153// "sharing",
154// "xrun_count",
155// "device_type",
156// "format_app",
157// "format_device",
158// };
159
Andy Hunga629bd12020-06-05 16:03:53 -0700160/**
161 * sendToStatsd is a helper method that sends the arguments to statsd
162 * and returns a pair { result, summary_string }.
163 */
164template <size_t N, typename ...Types>
165std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
166{
167 int result = 0;
168 std::stringstream ss;
169
170#ifdef STATSD_ENABLE
171 result = android::util::stats_write(args...);
172 ss << "result:" << result;
173#endif
174 ss << " { ";
175 stringutils::fieldPrint(ss, fields, args...);
176 ss << "}";
177 return { result, ss.str() };
178}
Andy Hung06f3aba2019-12-03 16:36:42 -0800179
180AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -0700181 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -0800182{
Andy Hunga629bd12020-06-05 16:03:53 -0700183 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800184 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800185
186 // Add action to save AnalyticsState if audioserver is restarted.
187 // This triggers on an item of "audio.flinger"
188 // with a property "event" set to "AudioFlinger" (the constructor).
189 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800190 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
191 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800192 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800193 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
194 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800195 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
196 *mAnalyticsState.get()));
197 // Note: get returns shared_ptr temp, whose lifetime is extended
198 // to end of full expression.
199 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800200 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700201
202 // Set up a timer to expire the previous audio state to save space.
203 // Use the transaction log size as a cookie to see if it is the
204 // same as before. A benign race is possible where a state is cleared early.
205 const size_t size = mPreviousAnalyticsState->transactionLog().size();
206 mTimedAction.postIn(
207 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
208 if (mPreviousAnalyticsState->transactionLog().size() == size) {
209 ALOGD("expiring previous audio state after %d seconds.",
210 PREVIOUS_STATE_EXPIRE_SEC);
211 mPreviousAnalyticsState->clear(); // removes data from the state.
212 }
213 });
Andy Hungea186fa2020-01-09 18:13:15 -0800214 }));
215
jiabin515eb092020-11-18 17:55:52 -0800216 // Handle legacy aaudio stream statistics
217 mActions.addAction(
218 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
219 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
220 std::make_shared<AnalyticsActions::Function>(
221 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
222 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_LEGACY);
223 }));
224
225 // Handle mmap aaudio stream statistics
226 mActions.addAction(
227 AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM "*." AMEDIAMETRICS_PROP_EVENT,
228 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM),
229 std::make_shared<AnalyticsActions::Function>(
230 [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
231 mAAudioStreamInfo.endAAudioStream(item, AAudioStreamInfo::CALLER_PATH_MMAP);
232 }));
233
Andy Hungea840382020-05-05 21:50:17 -0700234 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800235 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700236 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
237 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800238 std::make_shared<AnalyticsActions::Function>(
239 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700240 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800241 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700242
243 // Handle device use thread statistics
244 mActions.addAction(
245 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
246 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
247 std::make_shared<AnalyticsActions::Function>(
248 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700249 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700250 }));
251
252 // Handle device use track statistics
253 mActions.addAction(
254 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
255 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
256 std::make_shared<AnalyticsActions::Function>(
257 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700258 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700259 }));
260
Andy Hungea840382020-05-05 21:50:17 -0700261
262 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700263
264 // We track connections (not disconnections) for the time to connect.
265 // TODO: consider BT requests in their A2dp service
266 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
267 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
268 // AudioDeviceBroker.postA2dpActiveDeviceChange
269 mActions.addAction(
270 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700271 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700272 std::make_shared<AnalyticsActions::Function>(
273 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
274 mDeviceConnection.a2dpConnected(item);
275 }));
276 // If audio is active, we expect to see a createAudioPatch after the device is connected.
277 mActions.addAction(
278 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
279 std::string("createAudioPatch"),
280 std::make_shared<AnalyticsActions::Function>(
281 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
282 mDeviceConnection.createPatch(item);
283 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800284
Andy Hungea840382020-05-05 21:50:17 -0700285 // Called from BT service
286 mActions.addAction(
287 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
288 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
289 "." AMEDIAMETRICS_PROP_STATE,
290 "connected",
291 std::make_shared<AnalyticsActions::Function>(
292 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
293 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
294 }));
295
Joey Poomarin52989982020-03-05 17:40:49 +0800296 // Handle power usage
297 mActions.addAction(
298 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
299 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
300 std::make_shared<AnalyticsActions::Function>(
301 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
302 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
303 }));
304
305 mActions.addAction(
306 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
307 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
308 std::make_shared<AnalyticsActions::Function>(
309 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
310 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
311 }));
312
313 mActions.addAction(
314 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
315 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
316 std::make_shared<AnalyticsActions::Function>(
317 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
318 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
319 mAudioPowerUsage.checkMode(item);
320 }));
321
322 mActions.addAction(
323 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
324 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
325 std::make_shared<AnalyticsActions::Function>(
326 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
327 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
328 mAudioPowerUsage.checkVoiceVolume(item);
329 }));
330
331 mActions.addAction(
332 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
333 std::string("createAudioPatch"),
334 std::make_shared<AnalyticsActions::Function>(
335 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
336 mAudioPowerUsage.checkCreatePatch(item);
337 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800338}
339
340AudioAnalytics::~AudioAnalytics()
341{
342 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700343 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800344}
345
346status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800347 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800348{
Andy Hungea186fa2020-01-09 18:13:15 -0800349 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800350 status_t status = mAnalyticsState->submit(item, isTrusted);
351 if (status != NO_ERROR) return status; // may not be permitted.
352
353 // Only if the item was successfully submitted (permission)
354 // do we check triggered actions.
355 checkActions(item);
356 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800357}
358
Andy Hung709b91e2020-04-04 14:23:36 -0700359std::pair<std::string, int32_t> AudioAnalytics::dump(
360 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800361{
362 std::stringstream ss;
363 int32_t ll = lines;
364
365 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700366 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700367 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800368 ll -= l;
369 }
370 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800371 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800372 --ll;
373 }
374 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700375 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700376 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800377 ll -= l;
378 }
Joey Poomarin52989982020-03-05 17:40:49 +0800379
Andy Hunga629bd12020-06-05 16:03:53 -0700380 if (ll > 0) {
381 // Print the statsd atoms we sent out.
382 const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
383 const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
384 if ((size_t)ll >= n) {
385 if (n == 1) {
386 ss << "Statsd atoms: empty or truncated\n";
387 } else {
388 ss << "Statsd atoms:\n" << statsd;
389 }
390 ll -= n;
391 }
392 }
393
Joey Poomarin52989982020-03-05 17:40:49 +0800394 if (ll > 0 && prefix == nullptr) {
395 auto [s, l] = mAudioPowerUsage.dump(ll);
396 ss << s;
397 ll -= l;
398 }
Andy Hunga629bd12020-06-05 16:03:53 -0700399
Andy Hung06f3aba2019-12-03 16:36:42 -0800400 return { ss.str(), lines - ll };
401}
402
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800403void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
404{
405 auto actions = mActions.getActionsForItem(item); // internally locked.
406 // Execute actions with no lock held.
407 for (const auto& action : actions) {
408 (*action)(item);
409 }
410}
411
Andy Hungea186fa2020-01-09 18:13:15 -0800412// HELPER METHODS
413
414std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
415{
416 int32_t threadId_int32{};
417 if (mAnalyticsState->timeMachine().get(
418 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
419 return {};
420 }
421 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
422}
423
Andy Hungce9b6632020-04-28 20:15:17 -0700424// DeviceUse helper class.
425void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700426 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700427 const std::string& key = item->getKey();
428 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700429 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
430 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
431 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700432 - 1);
433 // deliver statistics
434 int64_t deviceTimeNs = 0;
435 mAudioAnalytics.mAnalyticsState->timeMachine().get(
436 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
437 std::string encoding;
438 mAudioAnalytics.mAnalyticsState->timeMachine().get(
439 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
440 int32_t frameCount = 0;
441 mAudioAnalytics.mAnalyticsState->timeMachine().get(
442 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700443 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700444 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700445 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700446 int32_t intervalCount = 0;
447 mAudioAnalytics.mAnalyticsState->timeMachine().get(
448 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700449 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700450 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700451 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700452 int32_t sampleRate = 0;
453 mAudioAnalytics.mAnalyticsState->timeMachine().get(
454 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700455 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700456 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700457 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700458
Andy Hungea840382020-05-05 21:50:17 -0700459 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700460 // Accumulate the bit flags for input and output devices.
461 std::stringstream oss;
462 long_enum_type_t outputDeviceBits{};
463 { // compute outputDevices
464 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700465 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700466 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
467 oss << device;
468 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700469 }
470 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700471 const std::string outputDevices = oss.str();
472
473 std::stringstream iss;
474 long_enum_type_t inputDeviceBits{};
475 { // compute inputDevices
476 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
477 for (const auto& [device, addr] : devaddrvec) {
478 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
479 iss << device;
480 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
481 }
482 }
483 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700484
485 // Get connected device name if from bluetooth.
486 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700487
488 std::string inputDeviceNames; // not filled currently.
489 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700490 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
491 isBluetooth = true;
Andy Hung3deef2b2020-07-17 12:58:54 -0700492 outputDeviceNames = SUPPRESSED;
493#if 0 // TODO(b/161554630) sanitize name
Andy Hungce9b6632020-04-28 20:15:17 -0700494 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700495 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700496 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700497 stringutils::replace(outputDeviceNames, "|", '?');
498 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
499 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
500 }
Andy Hung3deef2b2020-07-17 12:58:54 -0700501#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700502 }
503
Andy Hungea840382020-05-05 21:50:17 -0700504 switch (itemType) {
505 case RECORD: {
506 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700507 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
508 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700509
Andy Hungea840382020-05-05 21:50:17 -0700510 std::string packageName;
511 int64_t versionCode = 0;
512 int32_t uid = -1;
513 mAudioAnalytics.mAnalyticsState->timeMachine().get(
514 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
515 if (uid != -1) {
516 std::tie(packageName, versionCode) =
517 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
518 }
519
520 int32_t selectedDeviceId = 0;
521 mAudioAnalytics.mAnalyticsState->timeMachine().get(
522 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
523 std::string source;
524 mAudioAnalytics.mAnalyticsState->timeMachine().get(
525 key, AMEDIAMETRICS_PROP_SOURCE, &source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800526 // Android S
527 std::string logSessionId;
528 mAudioAnalytics.mAnalyticsState->timeMachine().get(
529 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700530
Andy Hung1ea842e2020-05-18 10:47:31 -0700531 const auto callerNameForStats =
532 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
533 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
534 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
535 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800536 // Android S
537 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hungea840382020-05-05 21:50:17 -0700538
Andy Hunga629bd12020-06-05 16:03:53 -0700539 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700540 << " id:" << id
541 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700542 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700543 << " deviceTimeNs:" << deviceTimeNs
544 << " encoding:" << encoding << "(" << encodingForStats
545 << ") frameCount:" << frameCount
546 << " intervalCount:" << intervalCount
547 << " sampleRate:" << sampleRate
548 << " flags:" << flags << "(" << flagsForStats
549 << ") packageName:" << packageName
550 << " selectedDeviceId:" << selectedDeviceId
551 << " callerName:" << callerName << "(" << callerNameForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800552 << ") source:" << source << "(" << sourceForStats
553 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
554 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700555 if (clientCalled // only log if client app called AudioRecord.
556 && mAudioAnalytics.mDeliverStatistics) {
557 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
558 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700559 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700560 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700561 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700562 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700563 , frameCount
564 , intervalCount
565 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700566 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700567
568 , packageName.c_str()
569 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700570 , ENUM_EXTRACT(callerNameForStats)
571 , ENUM_EXTRACT(sourceForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800572 , logSessionIdForStats.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700573 );
Andy Hunga629bd12020-06-05 16:03:53 -0700574 ALOGV("%s: statsd %s", __func__, str.c_str());
575 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700576 }
Andy Hungea840382020-05-05 21:50:17 -0700577 } break;
578 case THREAD: {
579 std::string type;
580 mAudioAnalytics.mAnalyticsState->timeMachine().get(
581 key, AMEDIAMETRICS_PROP_TYPE, &type);
582 int32_t underrun = 0; // zero for record types
583 mAudioAnalytics.mAnalyticsState->timeMachine().get(
584 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700585
586 const bool isInput = types::isInputThreadType(type);
587 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
588 const auto flagsForStats =
589 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
590 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
591 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
592
Andy Hunga629bd12020-06-05 16:03:53 -0700593 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700594 << " id:" << id
595 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
596 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700597 << ") inputDeviceNames:" << inputDeviceNames
598 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700599 << " deviceTimeNs:" << deviceTimeNs
600 << " encoding:" << encoding << "(" << encodingForStats
601 << ") frameCount:" << frameCount
602 << " intervalCount:" << intervalCount
603 << " sampleRate:" << sampleRate
604 << " underrun:" << underrun
605 << " flags:" << flags << "(" << flagsForStats
606 << ") type:" << type << "(" << typeForStats
607 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700608 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700609 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
610 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
611 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
612 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700613 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700614 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700615 , frameCount
616 , intervalCount
617 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700618 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700619 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700620 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700621 );
Andy Hunga629bd12020-06-05 16:03:53 -0700622 ALOGV("%s: statsd %s", __func__, str.c_str());
623 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700624 }
Andy Hungea840382020-05-05 21:50:17 -0700625 } break;
626 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700627 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700628 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
629 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
630
Andy Hungce9b6632020-04-28 20:15:17 -0700631 std::string contentType;
632 mAudioAnalytics.mAnalyticsState->timeMachine().get(
633 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
634 double deviceLatencyMs = 0.;
635 mAudioAnalytics.mAnalyticsState->timeMachine().get(
636 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
637 double deviceStartupMs = 0.;
638 mAudioAnalytics.mAnalyticsState->timeMachine().get(
639 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
640 double deviceVolume = 0.;
641 mAudioAnalytics.mAnalyticsState->timeMachine().get(
642 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
643 std::string packageName;
644 int64_t versionCode = 0;
645 int32_t uid = -1;
646 mAudioAnalytics.mAnalyticsState->timeMachine().get(
647 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
648 if (uid != -1) {
649 std::tie(packageName, versionCode) =
650 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
651 }
652 double playbackPitch = 0.;
653 mAudioAnalytics.mAnalyticsState->timeMachine().get(
654 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
655 double playbackSpeed = 0.;
656 mAudioAnalytics.mAnalyticsState->timeMachine().get(
657 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
658 int32_t selectedDeviceId = 0;
659 mAudioAnalytics.mAnalyticsState->timeMachine().get(
660 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700661 std::string streamType;
662 mAudioAnalytics.mAnalyticsState->timeMachine().get(
663 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700664 std::string traits;
665 mAudioAnalytics.mAnalyticsState->timeMachine().get(
666 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700667 int32_t underrun = 0;
668 mAudioAnalytics.mAnalyticsState->timeMachine().get(
669 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700670 std::string usage;
671 mAudioAnalytics.mAnalyticsState->timeMachine().get(
672 key, AMEDIAMETRICS_PROP_USAGE, &usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800673 // Android S
674 std::string logSessionId;
675 mAudioAnalytics.mAnalyticsState->timeMachine().get(
676 key, AMEDIAMETRICS_PROP_LOGSESSIONID, &logSessionId);
Andy Hungce9b6632020-04-28 20:15:17 -0700677
Andy Hung1ea842e2020-05-18 10:47:31 -0700678 const auto callerNameForStats =
679 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
680 const auto contentTypeForStats =
681 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
682 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
683 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
684 const auto streamTypeForStats =
685 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700686 const auto traitsForStats =
687 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700688 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
Andy Hungcbcfaa22021-02-23 13:54:49 -0800689 // Android S
690 const auto logSessionIdForStats = stringutils::sanitizeLogSessionId(logSessionId);
Andy Hung1ea842e2020-05-18 10:47:31 -0700691
Andy Hunga629bd12020-06-05 16:03:53 -0700692 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700693 << " id:" << id
694 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700695 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700696 << " deviceTimeNs:" << deviceTimeNs
697 << " encoding:" << encoding << "(" << encodingForStats
698 << ") frameCount:" << frameCount
699 << " intervalCount:" << intervalCount
700 << " sampleRate:" << sampleRate
701 << " underrun:" << underrun
702 << " flags:" << flags << "(" << flagsForStats
703 << ") callerName:" << callerName << "(" << callerNameForStats
704 << ") contentType:" << contentType << "(" << contentTypeForStats
705 << ") deviceLatencyMs:" << deviceLatencyMs
706 << " deviceStartupMs:" << deviceStartupMs
707 << " deviceVolume:" << deviceVolume
708 << " packageName:" << packageName
709 << " playbackPitch:" << playbackPitch
710 << " playbackSpeed:" << playbackSpeed
711 << " selectedDeviceId:" << selectedDeviceId
712 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700713 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700714 << ") usage:" << usage << "(" << usageForStats
Andy Hungcbcfaa22021-02-23 13:54:49 -0800715 << ") logSessionId:" << logSessionId << "(" << logSessionIdForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700716 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700717 if (clientCalled // only log if client app called AudioTracks
718 && mAudioAnalytics.mDeliverStatistics) {
719 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
720 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700721 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700722 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700723 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700724 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700725 , frameCount
726 , intervalCount
727 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700728 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700729 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700730 , packageName.c_str()
731 , (float)deviceLatencyMs
732 , (float)deviceStartupMs
733 , (float)deviceVolume
734 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700735 , ENUM_EXTRACT(streamTypeForStats)
736 , ENUM_EXTRACT(usageForStats)
737 , ENUM_EXTRACT(contentTypeForStats)
738 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700739 , ENUM_EXTRACT(traitsForStats)
Andy Hungcbcfaa22021-02-23 13:54:49 -0800740 , logSessionIdForStats.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700741 );
Andy Hunga629bd12020-06-05 16:03:53 -0700742 ALOGV("%s: statsd %s", __func__, str.c_str());
743 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700744 }
Andy Hungea840382020-05-05 21:50:17 -0700745 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700746 }
747
748 // Report this as needed.
749 if (isBluetooth) {
750 // report this for Bluetooth
751 }
752}
753
754// DeviceConnection helper class.
755void AudioAnalytics::DeviceConnection::a2dpConnected(
756 const std::shared_ptr<const android::mediametrics::Item> &item) {
757 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700758 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700759 {
760 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700761 mA2dpConnectionServiceNs = atNs;
762 ++mA2dpConnectionServices;
763
764 if (mA2dpConnectionRequestNs == 0) {
765 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
766 }
767 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700768 }
769 std::string name;
770 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700771 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
772 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700773}
774
775void AudioAnalytics::DeviceConnection::createPatch(
776 const std::shared_ptr<const android::mediametrics::Item> &item) {
777 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700778 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700779 const std::string& key = item->getKey();
780 std::string outputDevices;
781 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700782 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700783 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700784 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700785 if (mA2dpConnectionRequestNs == 0) {
786 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700787 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700788 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700789 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700790 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700791
Andy Hungea840382020-05-05 21:50:17 -0700792 mA2dpConnectionRequestNs = 0;
793 mA2dpConnectionServiceNs = 0;
794 ++mA2dpConnectionSuccesses;
795
Andy Hung1ea842e2020-05-18 10:47:31 -0700796 const auto connectionTimeMs = float(timeDiffNs * 1e-6);
797
798 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
799 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
800
Andy Hunga629bd12020-06-05 16:03:53 -0700801 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700802 << " A2DP SUCCESS"
803 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700804 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700805 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700806 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700807 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700808
809 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
810 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700811 , ENUM_EXTRACT(inputDeviceBits)
812 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700813 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700814 , types::DEVICE_CONNECTION_RESULT_SUCCESS
815 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700816 , /* connection_count */ 1
817 );
Andy Hunga629bd12020-06-05 16:03:53 -0700818 ALOGV("%s: statsd %s", __func__, str.c_str());
819 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700820 }
Andy Hungce9b6632020-04-28 20:15:17 -0700821 }
822}
823
Andy Hungea840382020-05-05 21:50:17 -0700824// Called through AudioManager when the BT service wants to enable
825void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
826 const std::shared_ptr<const android::mediametrics::Item> &item) {
827 const int64_t atNs = item->getTimestamp();
828 const std::string& key = item->getKey();
829 std::string state;
830 item->get(AMEDIAMETRICS_PROP_STATE, &state);
831 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700832
833 std::string name;
834 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700835 {
836 std::lock_guard l(mLock);
837 mA2dpConnectionRequestNs = atNs;
838 ++mA2dpConnectionRequests;
Andy Hung3deef2b2020-07-17 12:58:54 -0700839 mA2dpDeviceName = SUPPRESSED; // TODO(b/161554630) sanitize name
Andy Hungea840382020-05-05 21:50:17 -0700840 }
Andy Hunga629bd12020-06-05 16:03:53 -0700841 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
842 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700843 // TODO: attempt to cancel a timed event, rather than let it expire.
844 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
845}
846
Andy Hungce9b6632020-04-28 20:15:17 -0700847void AudioAnalytics::DeviceConnection::expire() {
848 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700849 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700850
Andy Hung1ea842e2020-05-18 10:47:31 -0700851 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700852 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
853 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
854
Andy Hungea840382020-05-05 21:50:17 -0700855 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700856 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700857
Andy Hunga629bd12020-06-05 16:03:53 -0700858 LOG(LOG_LEVEL) << "A2DP CANCEL"
859 << " outputDevices:" << outputDeviceBits
860 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700861 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700862 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
863 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700864 , ENUM_EXTRACT(inputDeviceBits)
865 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700866 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700867 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700868 , /* connection_time_ms */ 0.f
869 , /* connection_count */ 1
870 );
Andy Hunga629bd12020-06-05 16:03:53 -0700871 ALOGV("%s: statsd %s", __func__, str.c_str());
872 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700873 }
Andy Hungea840382020-05-05 21:50:17 -0700874 return;
875 }
876
877 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
878 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700879 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700880 mA2dpConnectionRequestNs = 0;
881 mA2dpConnectionServiceNs = 0;
882 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700883
Andy Hunga629bd12020-06-05 16:03:53 -0700884 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
885 << " outputDevices:" << outputDeviceBits
886 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700887 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700888 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
889 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700890 , ENUM_EXTRACT(inputDeviceBits)
891 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700892 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700893 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700894 , /* connection_time_ms */ 0.f
895 , /* connection_count */ 1
896 );
Andy Hunga629bd12020-06-05 16:03:53 -0700897 ALOGV("%s: statsd %s", __func__, str.c_str());
898 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700899 }
Andy Hungce9b6632020-04-28 20:15:17 -0700900}
901
jiabin515eb092020-11-18 17:55:52 -0800902void AudioAnalytics::AAudioStreamInfo::endAAudioStream(
903 const std::shared_ptr<const android::mediametrics::Item> &item, CallerPath path) const {
904 const std::string& key = item->getKey();
905
906 std::string callerNameStr;
907 mAudioAnalytics.mAnalyticsState->timeMachine().get(
908 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerNameStr);
909
910 const auto callerName = types::lookup<types::CALLER_NAME, int32_t>(callerNameStr);
911
912 std::string directionStr;
913 mAudioAnalytics.mAnalyticsState->timeMachine().get(
914 key, AMEDIAMETRICS_PROP_DIRECTION, &directionStr);
915 const auto direction = types::lookup<types::AAUDIO_DIRECTION, int32_t>(directionStr);
916
917 int32_t framesPerBurst = -1;
918 mAudioAnalytics.mAnalyticsState->timeMachine().get(
919 key, AMEDIAMETRICS_PROP_BURSTFRAMES, &framesPerBurst);
920
921 int32_t bufferSizeInFrames = -1;
922 mAudioAnalytics.mAnalyticsState->timeMachine().get(
923 key, AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, &bufferSizeInFrames);
924
925 int32_t bufferCapacityInFrames = -1;
926 mAudioAnalytics.mAnalyticsState->timeMachine().get(
927 key, AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, &bufferCapacityInFrames);
928
929 int32_t channelCount = -1;
930 mAudioAnalytics.mAnalyticsState->timeMachine().get(
931 key, AMEDIAMETRICS_PROP_CHANNELCOUNT, &channelCount);
932
933 int64_t totalFramesTransferred = -1;
934 // TODO: log and get total frames transferred
935
936 std::string perfModeRequestedStr;
937 mAudioAnalytics.mAnalyticsState->timeMachine().get(
938 key, AMEDIAMETRICS_PROP_PERFORMANCEMODE, &perfModeRequestedStr);
939 const auto perfModeRequested =
940 types::lookup<types::AAUDIO_PERFORMANCE_MODE, int32_t>(perfModeRequestedStr);
941
942 int32_t perfModeActual = 0;
943 // TODO: log and get actual performance mode
944
945 std::string sharingModeStr;
946 mAudioAnalytics.mAnalyticsState->timeMachine().get(
947 key, AMEDIAMETRICS_PROP_SHARINGMODE, &sharingModeStr);
948 const auto sharingMode = types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeStr);
949
950 int32_t xrunCount = -1;
951 mAudioAnalytics.mAnalyticsState->timeMachine().get(
952 key, AMEDIAMETRICS_PROP_UNDERRUN, &xrunCount);
953
954 std::string deviceType;
955 // TODO: only routed device id is logged, but no device type
956
957 int32_t formatApp = 0;
958 // TODO: log format from app
959
960 std::string formatDeviceStr;
961 mAudioAnalytics.mAnalyticsState->timeMachine().get(
962 key, AMEDIAMETRICS_PROP_ENCODING, &formatDeviceStr);
963 const auto formatDevice = types::lookup<types::ENCODING, int32_t>(formatDeviceStr);
964
965 LOG(LOG_LEVEL) << "key:" << key
966 << " caller_name:" << callerName << "(" << callerNameStr << ")"
967 << " path:" << path
968 << " direction:" << direction << "(" << directionStr << ")"
969 << " frames_per_burst:" << framesPerBurst
970 << " buffer_size:" << bufferSizeInFrames
971 << " buffer_capacity:" << bufferCapacityInFrames
972 << " channel_count:" << channelCount
973 << " total_frames_transferred:" << totalFramesTransferred
974 << " perf_mode_requested:" << perfModeRequested << "(" << perfModeRequestedStr << ")"
975 << " perf_mode_actual:" << perfModeActual
976 << " sharing:" << sharingMode << "(" << sharingModeStr << ")"
977 << " xrun_count:" << xrunCount
978 << " device_type:" << deviceType
979 << " format_app:" << formatApp
980 << " format_device: " << formatDevice << "(" << formatDeviceStr << ")";
981
982 // TODO: send the metric to statsd when the proto is ready
983 // if (mAudioAnalytics.mDeliverStatistics) {
984 // const auto [ result, str ] = sendToStatsd(AAudioStreamFields,
985 // CONDITION(android::util::MEDIAMETRICS_AAUDIOSTREAM_REPORTED)
986 // , callerName
987 // , path
988 // , direction
989 // , framesPerBurst
990 // , bufferSizeInFrames
991 // , bufferCapacityInFrames
992 // , channelCount
993 // , totalFramesTransferred
994 // , perfModeRequested
995 // , perfModeActual
996 // , sharingMode
997 // , xrunCount
998 // , deviceType.c_str()
999 // , formatApp
1000 // , formatDevice
1001 // );
1002 // ALOGV("%s: statsd %s", __func__, str.c_str());
1003 // mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
1004 // }
1005}
1006
Andy Hung3ab1b322020-05-18 10:47:31 -07001007} // namespace android::mediametrics