blob: 800f099c21f6a65b8ed7d24fdf01cb8d4482a2d8 [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 Hungce9b6632020-04-28 20:15:17 -070034// Enable for testing of delivery to statsd
Andy Hung1ea842e2020-05-18 10:47:31 -070035//#define STATSD
36
37// Transmit to statsd in integer or strings
38//#define USE_INT
39
40#ifdef USE_INT
41using short_enum_type_t = int32_t;
42using long_enum_type_t = int64_t;
43#define ENUM_EXTRACT(x) (x)
44#else
45using short_enum_type_t = std::string;
46using long_enum_type_t = std::string;
47#define ENUM_EXTRACT(x) (x).c_str()
48#endif
49
50using android::base::DEBUG;
Andy Hung06f3aba2019-12-03 16:36:42 -080051
52namespace android::mediametrics {
53
54AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -070055 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -080056{
Andy Hung1ea842e2020-05-18 10:47:31 -070057 SetMinimumLogSeverity(DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -080058 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -080059
60 // Add action to save AnalyticsState if audioserver is restarted.
61 // This triggers on an item of "audio.flinger"
62 // with a property "event" set to "AudioFlinger" (the constructor).
63 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -080064 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
65 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -080066 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -080067 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
68 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -080069 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
70 *mAnalyticsState.get()));
71 // Note: get returns shared_ptr temp, whose lifetime is extended
72 // to end of full expression.
73 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -080074 // Perhaps report this.
75 }));
76
Andy Hungea840382020-05-05 21:50:17 -070077 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -080078 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -070079 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
80 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -080081 std::make_shared<AnalyticsActions::Function>(
82 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -070083 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -080084 }));
Andy Hungce9b6632020-04-28 20:15:17 -070085
86 // Handle device use thread statistics
87 mActions.addAction(
88 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
89 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
90 std::make_shared<AnalyticsActions::Function>(
91 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -070092 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -070093 }));
94
95 // Handle device use track statistics
96 mActions.addAction(
97 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
98 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
99 std::make_shared<AnalyticsActions::Function>(
100 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700101 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700102 }));
103
Andy Hungea840382020-05-05 21:50:17 -0700104
105 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700106
107 // We track connections (not disconnections) for the time to connect.
108 // TODO: consider BT requests in their A2dp service
109 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
110 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
111 // AudioDeviceBroker.postA2dpActiveDeviceChange
112 mActions.addAction(
113 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700114 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700115 std::make_shared<AnalyticsActions::Function>(
116 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
117 mDeviceConnection.a2dpConnected(item);
118 }));
119 // If audio is active, we expect to see a createAudioPatch after the device is connected.
120 mActions.addAction(
121 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
122 std::string("createAudioPatch"),
123 std::make_shared<AnalyticsActions::Function>(
124 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
125 mDeviceConnection.createPatch(item);
126 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800127
Andy Hungea840382020-05-05 21:50:17 -0700128 // Called from BT service
129 mActions.addAction(
130 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
131 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
132 "." AMEDIAMETRICS_PROP_STATE,
133 "connected",
134 std::make_shared<AnalyticsActions::Function>(
135 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
136 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
137 }));
138
Joey Poomarin52989982020-03-05 17:40:49 +0800139 // Handle power usage
140 mActions.addAction(
141 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
142 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
143 std::make_shared<AnalyticsActions::Function>(
144 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
145 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
146 }));
147
148 mActions.addAction(
149 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
150 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
151 std::make_shared<AnalyticsActions::Function>(
152 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
153 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
154 }));
155
156 mActions.addAction(
157 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
158 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
159 std::make_shared<AnalyticsActions::Function>(
160 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
161 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
162 mAudioPowerUsage.checkMode(item);
163 }));
164
165 mActions.addAction(
166 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
167 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
168 std::make_shared<AnalyticsActions::Function>(
169 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
170 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
171 mAudioPowerUsage.checkVoiceVolume(item);
172 }));
173
174 mActions.addAction(
175 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
176 std::string("createAudioPatch"),
177 std::make_shared<AnalyticsActions::Function>(
178 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
179 mAudioPowerUsage.checkCreatePatch(item);
180 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800181}
182
183AudioAnalytics::~AudioAnalytics()
184{
185 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700186 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800187}
188
189status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800190 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800191{
Andy Hungea186fa2020-01-09 18:13:15 -0800192 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800193 status_t status = mAnalyticsState->submit(item, isTrusted);
194 if (status != NO_ERROR) return status; // may not be permitted.
195
196 // Only if the item was successfully submitted (permission)
197 // do we check triggered actions.
198 checkActions(item);
199 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800200}
201
Andy Hung709b91e2020-04-04 14:23:36 -0700202std::pair<std::string, int32_t> AudioAnalytics::dump(
203 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800204{
205 std::stringstream ss;
206 int32_t ll = lines;
207
208 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700209 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700210 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800211 ll -= l;
212 }
213 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800214 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800215 --ll;
216 }
217 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700218 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700219 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800220 ll -= l;
221 }
Joey Poomarin52989982020-03-05 17:40:49 +0800222
223 if (ll > 0 && prefix == nullptr) {
224 auto [s, l] = mAudioPowerUsage.dump(ll);
225 ss << s;
226 ll -= l;
227 }
Andy Hung06f3aba2019-12-03 16:36:42 -0800228 return { ss.str(), lines - ll };
229}
230
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800231void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
232{
233 auto actions = mActions.getActionsForItem(item); // internally locked.
234 // Execute actions with no lock held.
235 for (const auto& action : actions) {
236 (*action)(item);
237 }
238}
239
Andy Hungea186fa2020-01-09 18:13:15 -0800240// HELPER METHODS
241
242std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
243{
244 int32_t threadId_int32{};
245 if (mAnalyticsState->timeMachine().get(
246 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
247 return {};
248 }
249 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
250}
251
Andy Hungce9b6632020-04-28 20:15:17 -0700252// DeviceUse helper class.
253void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700254 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700255 const std::string& key = item->getKey();
256 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700257 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
258 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
259 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700260 - 1);
261 // deliver statistics
262 int64_t deviceTimeNs = 0;
263 mAudioAnalytics.mAnalyticsState->timeMachine().get(
264 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
265 std::string encoding;
266 mAudioAnalytics.mAnalyticsState->timeMachine().get(
267 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
268 int32_t frameCount = 0;
269 mAudioAnalytics.mAnalyticsState->timeMachine().get(
270 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700271 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700272 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700273 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700274 int32_t intervalCount = 0;
275 mAudioAnalytics.mAnalyticsState->timeMachine().get(
276 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700277 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700278 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700279 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700280 int32_t sampleRate = 0;
281 mAudioAnalytics.mAnalyticsState->timeMachine().get(
282 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700283 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700284 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700285 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700286
Andy Hungea840382020-05-05 21:50:17 -0700287 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700288 // Accumulate the bit flags for input and output devices.
289 std::stringstream oss;
290 long_enum_type_t outputDeviceBits{};
291 { // compute outputDevices
292 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700293 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700294 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
295 oss << device;
296 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700297 }
298 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700299 const std::string outputDevices = oss.str();
300
301 std::stringstream iss;
302 long_enum_type_t inputDeviceBits{};
303 { // compute inputDevices
304 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
305 for (const auto& [device, addr] : devaddrvec) {
306 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
307 iss << device;
308 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
309 }
310 }
311 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700312
313 // Get connected device name if from bluetooth.
314 bool isBluetooth = false;
Andy Hungea840382020-05-05 21:50:17 -0700315 std::string deviceNames; // we only have one device name at this time.
Andy Hungce9b6632020-04-28 20:15:17 -0700316 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
317 isBluetooth = true;
318 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700319 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &deviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700320 // Remove | if present
321 stringutils::replace(deviceNames, "|", '?');
Andy Hungce9b6632020-04-28 20:15:17 -0700322 }
323
Andy Hungea840382020-05-05 21:50:17 -0700324 switch (itemType) {
325 case RECORD: {
326 std::string callerName;
327 mAudioAnalytics.mAnalyticsState->timeMachine().get(
328 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
Andy Hungce9b6632020-04-28 20:15:17 -0700329
Andy Hungea840382020-05-05 21:50:17 -0700330 std::string packageName;
331 int64_t versionCode = 0;
332 int32_t uid = -1;
333 mAudioAnalytics.mAnalyticsState->timeMachine().get(
334 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
335 if (uid != -1) {
336 std::tie(packageName, versionCode) =
337 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
338 }
339
340 int32_t selectedDeviceId = 0;
341 mAudioAnalytics.mAnalyticsState->timeMachine().get(
342 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
343 std::string source;
344 mAudioAnalytics.mAnalyticsState->timeMachine().get(
345 key, AMEDIAMETRICS_PROP_SOURCE, &source);
346
Andy Hung1ea842e2020-05-18 10:47:31 -0700347 const auto callerNameForStats =
348 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
349 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
350 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
351 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungea840382020-05-05 21:50:17 -0700352
Andy Hung1ea842e2020-05-18 10:47:31 -0700353 LOG(DEBUG) << "key:" << key
354 << " id:" << id
355 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
356 << ") deviceNames:" << deviceNames
357 << " deviceTimeNs:" << deviceTimeNs
358 << " encoding:" << encoding << "(" << encodingForStats
359 << ") frameCount:" << frameCount
360 << " intervalCount:" << intervalCount
361 << " sampleRate:" << sampleRate
362 << " flags:" << flags << "(" << flagsForStats
363 << ") packageName:" << packageName
364 << " selectedDeviceId:" << selectedDeviceId
365 << " callerName:" << callerName << "(" << callerNameForStats
366 << ") source:" << source << "(" << sourceForStats << ")";
Andy Hungea840382020-05-05 21:50:17 -0700367#ifdef STATSD
368 if (mAudioAnalytics.mDeliverStatistics) {
369 (void)android::util::stats_write(
370 android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED
Andy Hung1ea842e2020-05-18 10:47:31 -0700371 , ENUM_EXTRACT(inputDeviceBits)
Andy Hungea840382020-05-05 21:50:17 -0700372 , deviceNames.c_str()
373 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700374 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700375 , frameCount
376 , intervalCount
377 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700378 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700379
380 , packageName.c_str()
381 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700382 , ENUM_EXTRACT(callerNameForStats)
383 , ENUM_EXTRACT(sourceForStats)
Andy Hungea840382020-05-05 21:50:17 -0700384 );
385 }
386#endif
387 } break;
388 case THREAD: {
389 std::string type;
390 mAudioAnalytics.mAnalyticsState->timeMachine().get(
391 key, AMEDIAMETRICS_PROP_TYPE, &type);
392 int32_t underrun = 0; // zero for record types
393 mAudioAnalytics.mAnalyticsState->timeMachine().get(
394 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700395
396 const bool isInput = types::isInputThreadType(type);
397 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
398 const auto flagsForStats =
399 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
400 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
401 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
402
403 LOG(DEBUG) << "key:" << key
404 << " id:" << id
405 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
406 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
407 << ") deviceNames:" << deviceNames
408 << " deviceTimeNs:" << deviceTimeNs
409 << " encoding:" << encoding << "(" << encodingForStats
410 << ") frameCount:" << frameCount
411 << " intervalCount:" << intervalCount
412 << " sampleRate:" << sampleRate
413 << " underrun:" << underrun
414 << " flags:" << flags << "(" << flagsForStats
415 << ") type:" << type << "(" << typeForStats
416 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700417#ifdef STATSD
418 if (mAudioAnalytics.mDeliverStatistics) {
419 (void)android::util::stats_write(
420 android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED
Andy Hung1ea842e2020-05-18 10:47:31 -0700421 , ENUM_EXTRACT(inputDeviceBits)
422 , ENUM_EXTRACT(outputDeviceBits)
Andy Hungea840382020-05-05 21:50:17 -0700423 , deviceNames.c_str()
424 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700425 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700426 , frameCount
427 , intervalCount
428 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700429 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700430 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700431 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700432 );
433 }
434#endif
435 } break;
436 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700437 std::string callerName;
438 mAudioAnalytics.mAnalyticsState->timeMachine().get(
439 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
440 std::string contentType;
441 mAudioAnalytics.mAnalyticsState->timeMachine().get(
442 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
443 double deviceLatencyMs = 0.;
444 mAudioAnalytics.mAnalyticsState->timeMachine().get(
445 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
446 double deviceStartupMs = 0.;
447 mAudioAnalytics.mAnalyticsState->timeMachine().get(
448 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
449 double deviceVolume = 0.;
450 mAudioAnalytics.mAnalyticsState->timeMachine().get(
451 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
452 std::string packageName;
453 int64_t versionCode = 0;
454 int32_t uid = -1;
455 mAudioAnalytics.mAnalyticsState->timeMachine().get(
456 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
457 if (uid != -1) {
458 std::tie(packageName, versionCode) =
459 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
460 }
461 double playbackPitch = 0.;
462 mAudioAnalytics.mAnalyticsState->timeMachine().get(
463 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
464 double playbackSpeed = 0.;
465 mAudioAnalytics.mAnalyticsState->timeMachine().get(
466 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
467 int32_t selectedDeviceId = 0;
468 mAudioAnalytics.mAnalyticsState->timeMachine().get(
469 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700470 std::string streamType;
471 mAudioAnalytics.mAnalyticsState->timeMachine().get(
472 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
473 int32_t underrun = 0;
474 mAudioAnalytics.mAnalyticsState->timeMachine().get(
475 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700476 std::string usage;
477 mAudioAnalytics.mAnalyticsState->timeMachine().get(
478 key, AMEDIAMETRICS_PROP_USAGE, &usage);
479
Andy Hung1ea842e2020-05-18 10:47:31 -0700480 const auto callerNameForStats =
481 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
482 const auto contentTypeForStats =
483 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
484 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
485 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
486 const auto streamTypeForStats =
487 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
488 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
489
490 LOG(DEBUG) << "key:" << key
491 << " id:" << id
492 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
493 << ") deviceNames:" << deviceNames
494 << " deviceTimeNs:" << deviceTimeNs
495 << " encoding:" << encoding << "(" << encodingForStats
496 << ") frameCount:" << frameCount
497 << " intervalCount:" << intervalCount
498 << " sampleRate:" << sampleRate
499 << " underrun:" << underrun
500 << " flags:" << flags << "(" << flagsForStats
501 << ") callerName:" << callerName << "(" << callerNameForStats
502 << ") contentType:" << contentType << "(" << contentTypeForStats
503 << ") deviceLatencyMs:" << deviceLatencyMs
504 << " deviceStartupMs:" << deviceStartupMs
505 << " deviceVolume:" << deviceVolume
506 << " packageName:" << packageName
507 << " playbackPitch:" << playbackPitch
508 << " playbackSpeed:" << playbackSpeed
509 << " selectedDeviceId:" << selectedDeviceId
510 << " streamType:" << streamType << "(" << streamTypeForStats
511 << ") usage:" << usage << "(" << usageForStats
512 << ")";
Andy Hungce9b6632020-04-28 20:15:17 -0700513#ifdef STATSD
514 if (mAudioAnalytics.mDeliverStatistics) {
515 (void)android::util::stats_write(
516 android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED
Andy Hung1ea842e2020-05-18 10:47:31 -0700517 , ENUM_EXTRACT(outputDeviceBits)
Andy Hungea840382020-05-05 21:50:17 -0700518 , deviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700519 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700520 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700521 , frameCount
522 , intervalCount
523 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700524 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700525 , underrun
526
527 , packageName.c_str()
528 , (float)deviceLatencyMs
529 , (float)deviceStartupMs
530 , (float)deviceVolume
531 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700532 , ENUM_EXTRACT(streamTypeForStats)
533 , ENUM_EXTRACT(usageForStats)
534 , ENUM_EXTRACT(contentTypeForStats)
535 , ENUM_EXTRACT(callerNameForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700536 );
537 }
538#endif
Andy Hungea840382020-05-05 21:50:17 -0700539 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700540 }
541
542 // Report this as needed.
543 if (isBluetooth) {
544 // report this for Bluetooth
545 }
546}
547
548// DeviceConnection helper class.
549void AudioAnalytics::DeviceConnection::a2dpConnected(
550 const std::shared_ptr<const android::mediametrics::Item> &item) {
551 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700552 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700553 {
554 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700555 mA2dpConnectionServiceNs = atNs;
556 ++mA2dpConnectionServices;
557
558 if (mA2dpConnectionRequestNs == 0) {
559 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
560 }
561 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700562 }
563 std::string name;
564 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700565 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
566 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700567}
568
569void AudioAnalytics::DeviceConnection::createPatch(
570 const std::shared_ptr<const android::mediametrics::Item> &item) {
571 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700572 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700573 const std::string& key = item->getKey();
574 std::string outputDevices;
575 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700576 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700577 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700578 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700579 if (mA2dpConnectionRequestNs == 0) {
580 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700581 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700582 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700583 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700584 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700585
Andy Hungea840382020-05-05 21:50:17 -0700586 mA2dpConnectionRequestNs = 0;
587 mA2dpConnectionServiceNs = 0;
588 ++mA2dpConnectionSuccesses;
589
Andy Hung1ea842e2020-05-18 10:47:31 -0700590 const auto connectionTimeMs = float(timeDiffNs * 1e-6);
591
592 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
593 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
594
595 LOG(DEBUG) << "key:" << key
596 << " A2DP SUCCESS"
597 << " outputDevices:" << outputDeviceBits
598 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700599#ifdef STATSD
600 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700601 const long_enum_type_t inputDeviceBits{};
Andy Hungea840382020-05-05 21:50:17 -0700602 (void)android::util::stats_write(
603 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
Andy Hung1ea842e2020-05-18 10:47:31 -0700604 , ENUM_EXTRACT(inputDeviceBits)
605 , ENUM_EXTRACT(outputDeviceBits)
606 , types::DEVICE_CONNECTION_RESULT_SUCCESS
607 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700608 , /* connection_count */ 1
609 );
610 }
611#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700612 }
613}
614
Andy Hungea840382020-05-05 21:50:17 -0700615// Called through AudioManager when the BT service wants to enable
616void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
617 const std::shared_ptr<const android::mediametrics::Item> &item) {
618 const int64_t atNs = item->getTimestamp();
619 const std::string& key = item->getKey();
620 std::string state;
621 item->get(AMEDIAMETRICS_PROP_STATE, &state);
622 if (state != "connected") return;
623 {
624 std::lock_guard l(mLock);
625 mA2dpConnectionRequestNs = atNs;
626 ++mA2dpConnectionRequests;
627 }
628 ALOGD("(key=%s) a2dp connection request atNs:%lld",
629 key.c_str(), (long long)atNs);
630 // TODO: attempt to cancel a timed event, rather than let it expire.
631 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
632}
633
Andy Hungce9b6632020-04-28 20:15:17 -0700634void AudioAnalytics::DeviceConnection::expire() {
635 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700636 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700637
638#ifdef STATSD
639 const long_enum_type_t inputDeviceBits{};
640#endif
641 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
642 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
643
Andy Hungea840382020-05-05 21:50:17 -0700644 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700645 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700646
Andy Hung1ea842e2020-05-18 10:47:31 -0700647 LOG(DEBUG) << "A2DP CANCEL"
648 << " outputDevices:" << outputDeviceBits;
Andy Hungea840382020-05-05 21:50:17 -0700649#ifdef STATSD
650 if (mAudioAnalytics.mDeliverStatistics) {
651 (void)android::util::stats_write(
652 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
Andy Hung1ea842e2020-05-18 10:47:31 -0700653 , ENUM_EXTRACT(inputDeviceBits)
654 , ENUM_EXTRACT(outputDeviceBits)
655 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700656 , /* connection_time_ms */ 0.f
657 , /* connection_count */ 1
658 );
659 }
660#endif
661 return;
662 }
663
664 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
665 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700666 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700667 mA2dpConnectionRequestNs = 0;
668 mA2dpConnectionServiceNs = 0;
669 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700670
671 LOG(DEBUG) << "A2DP UNKNOWN"
672 << " outputDevices:" << outputDeviceBits;
Andy Hungea840382020-05-05 21:50:17 -0700673#ifdef STATSD
674 if (mAudioAnalytics.mDeliverStatistics) {
675 (void)android::util::stats_write(
676 android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED
Andy Hung1ea842e2020-05-18 10:47:31 -0700677 , ENUM_EXTRACT(inputDeviceBits)
678 , ENUM_EXTRACT(outputDeviceBits)
679 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700680 , /* connection_time_ms */ 0.f
681 , /* connection_count */ 1
682 );
683 }
684#endif
Andy Hungce9b6632020-04-28 20:15:17 -0700685}
686
Andy Hung3ab1b322020-05-18 10:47:31 -0700687} // namespace android::mediametrics