blob: 29801a4ba611e06b4b850d76c57194a46913f84d [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.
46static constexpr size_t STATSD_DEVICE_NAME_MAX_LENGTH = 32;
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 Hunga629bd12020-06-05 16:03:53 -070069/*
70 * For logging purposes, we list all of the MediaMetrics atom fields,
71 * which can then be associated with consecutive arguments to the statsd write.
72 */
73
74static constexpr const char * const AudioRecordDeviceUsageFields[] = {
75 "mediametrics_audiorecorddeviceusage_reported", // proto number
76 "devices",
77 "device_names",
78 "device_time_nanos",
79 "encoding",
80 "frame_count",
81 "interval_count",
82 "sample_rate",
83 "flags",
84 "package_name",
85 "selected_device_id",
86 "caller",
87 "source",
88};
89
90static constexpr const char * const AudioThreadDeviceUsageFields[] = {
91 "mediametrics_audiothreaddeviceusage_reported",
92 "devices",
93 "device_names",
94 "device_time_nanos",
95 "encoding",
96 "frame_count",
97 "interval_count",
98 "sample_rate",
99 "flags",
100 "xruns",
101 "type",
102};
103
104static constexpr const char * const AudioTrackDeviceUsageFields[] = {
105 "mediametrics_audiotrackdeviceusage_reported",
106 "devices",
107 "device_names",
108 "device_time_nanos",
109 "encoding",
110 "frame_count",
111 "interval_count",
112 "sample_rate",
113 "flags",
114 "xruns",
115 "package_name",
116 "device_latency_millis",
117 "device_startup_millis",
118 "device_volume",
119 "selected_device_id",
120 "stream_type",
121 "usage",
122 "content_type",
123 "caller",
124 "traits",
125};
126
127static constexpr const char * const AudioDeviceConnectionFields[] = {
128 "mediametrics_audiodeviceconnection_reported",
129 "input_devices",
130 "output_devices",
131 "device_names",
132 "result",
133 "time_to_connect_millis",
134 "connection_count",
135};
136
137/**
138 * sendToStatsd is a helper method that sends the arguments to statsd
139 * and returns a pair { result, summary_string }.
140 */
141template <size_t N, typename ...Types>
142std::pair<int, std::string> sendToStatsd(const char * const (& fields)[N], Types ... args)
143{
144 int result = 0;
145 std::stringstream ss;
146
147#ifdef STATSD_ENABLE
148 result = android::util::stats_write(args...);
149 ss << "result:" << result;
150#endif
151 ss << " { ";
152 stringutils::fieldPrint(ss, fields, args...);
153 ss << "}";
154 return { result, ss.str() };
155}
Andy Hung06f3aba2019-12-03 16:36:42 -0800156
157AudioAnalytics::AudioAnalytics()
Andy Hung1ea842e2020-05-18 10:47:31 -0700158 : mDeliverStatistics(property_get_bool(PROP_AUDIO_ANALYTICS_CLOUD_ENABLED, true))
Andy Hung06f3aba2019-12-03 16:36:42 -0800159{
Andy Hunga629bd12020-06-05 16:03:53 -0700160 SetMinimumLogSeverity(android::base::DEBUG); // for LOG().
Andy Hung06f3aba2019-12-03 16:36:42 -0800161 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800162
163 // Add action to save AnalyticsState if audioserver is restarted.
164 // This triggers on an item of "audio.flinger"
165 // with a property "event" set to "AudioFlinger" (the constructor).
166 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -0800167 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
168 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800169 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -0800170 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
171 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800172 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
173 *mAnalyticsState.get()));
174 // Note: get returns shared_ptr temp, whose lifetime is extended
175 // to end of full expression.
176 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -0800177 // Perhaps report this.
Andy Hungb18f5062020-06-18 23:10:08 -0700178
179 // Set up a timer to expire the previous audio state to save space.
180 // Use the transaction log size as a cookie to see if it is the
181 // same as before. A benign race is possible where a state is cleared early.
182 const size_t size = mPreviousAnalyticsState->transactionLog().size();
183 mTimedAction.postIn(
184 std::chrono::seconds(PREVIOUS_STATE_EXPIRE_SEC), [this, size](){
185 if (mPreviousAnalyticsState->transactionLog().size() == size) {
186 ALOGD("expiring previous audio state after %d seconds.",
187 PREVIOUS_STATE_EXPIRE_SEC);
188 mPreviousAnalyticsState->clear(); // removes data from the state.
189 }
190 });
Andy Hungea186fa2020-01-09 18:13:15 -0800191 }));
192
Andy Hungea840382020-05-05 21:50:17 -0700193 // Handle device use record statistics
Andy Hungea186fa2020-01-09 18:13:15 -0800194 mActions.addAction(
Andy Hungea840382020-05-05 21:50:17 -0700195 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
196 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
Andy Hungea186fa2020-01-09 18:13:15 -0800197 std::make_shared<AnalyticsActions::Function>(
198 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700199 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::RECORD);
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800200 }));
Andy Hungce9b6632020-04-28 20:15:17 -0700201
202 // Handle device use thread statistics
203 mActions.addAction(
204 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
205 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
206 std::make_shared<AnalyticsActions::Function>(
207 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700208 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::THREAD);
Andy Hungce9b6632020-04-28 20:15:17 -0700209 }));
210
211 // Handle device use track statistics
212 mActions.addAction(
213 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
214 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
215 std::make_shared<AnalyticsActions::Function>(
216 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
Andy Hungea840382020-05-05 21:50:17 -0700217 mDeviceUse.endAudioIntervalGroup(item, DeviceUse::TRACK);
Andy Hungce9b6632020-04-28 20:15:17 -0700218 }));
219
Andy Hungea840382020-05-05 21:50:17 -0700220
221 // Handle device connection statistics
Andy Hungce9b6632020-04-28 20:15:17 -0700222
223 // We track connections (not disconnections) for the time to connect.
224 // TODO: consider BT requests in their A2dp service
225 // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
226 // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
227 // AudioDeviceBroker.postA2dpActiveDeviceChange
228 mActions.addAction(
229 "audio.device.a2dp.state",
Andy Hungea840382020-05-05 21:50:17 -0700230 "connected",
Andy Hungce9b6632020-04-28 20:15:17 -0700231 std::make_shared<AnalyticsActions::Function>(
232 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
233 mDeviceConnection.a2dpConnected(item);
234 }));
235 // If audio is active, we expect to see a createAudioPatch after the device is connected.
236 mActions.addAction(
237 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
238 std::string("createAudioPatch"),
239 std::make_shared<AnalyticsActions::Function>(
240 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
241 mDeviceConnection.createPatch(item);
242 }));
Joey Poomarin52989982020-03-05 17:40:49 +0800243
Andy Hungea840382020-05-05 21:50:17 -0700244 // Called from BT service
245 mActions.addAction(
246 AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE
247 "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent"
248 "." AMEDIAMETRICS_PROP_STATE,
249 "connected",
250 std::make_shared<AnalyticsActions::Function>(
251 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
252 mDeviceConnection.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(item);
253 }));
254
Joey Poomarin52989982020-03-05 17:40:49 +0800255 // Handle power usage
256 mActions.addAction(
257 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
258 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
259 std::make_shared<AnalyticsActions::Function>(
260 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
261 mAudioPowerUsage.checkTrackRecord(item, true /* isTrack */);
262 }));
263
264 mActions.addAction(
265 AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD "*." AMEDIAMETRICS_PROP_EVENT,
266 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
267 std::make_shared<AnalyticsActions::Function>(
268 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
269 mAudioPowerUsage.checkTrackRecord(item, false /* isTrack */);
270 }));
271
272 mActions.addAction(
273 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
274 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETMODE),
275 std::make_shared<AnalyticsActions::Function>(
276 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
277 // ALOGD("(key=%s) Audioflinger setMode", item->getKey().c_str());
278 mAudioPowerUsage.checkMode(item);
279 }));
280
281 mActions.addAction(
282 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
283 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_SETVOICEVOLUME),
284 std::make_shared<AnalyticsActions::Function>(
285 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
286 // ALOGD("(key=%s) Audioflinger setVoiceVolume", item->getKey().c_str());
287 mAudioPowerUsage.checkVoiceVolume(item);
288 }));
289
290 mActions.addAction(
291 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
292 std::string("createAudioPatch"),
293 std::make_shared<AnalyticsActions::Function>(
294 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
295 mAudioPowerUsage.checkCreatePatch(item);
296 }));
Andy Hung06f3aba2019-12-03 16:36:42 -0800297}
298
299AudioAnalytics::~AudioAnalytics()
300{
301 ALOGD("%s", __func__);
Andy Hungce9b6632020-04-28 20:15:17 -0700302 mTimedAction.quit(); // ensure no deferred access during destructor.
Andy Hung06f3aba2019-12-03 16:36:42 -0800303}
304
305status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -0800306 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -0800307{
Andy Hungea186fa2020-01-09 18:13:15 -0800308 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800309 status_t status = mAnalyticsState->submit(item, isTrusted);
310 if (status != NO_ERROR) return status; // may not be permitted.
311
312 // Only if the item was successfully submitted (permission)
313 // do we check triggered actions.
314 checkActions(item);
315 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800316}
317
Andy Hung709b91e2020-04-04 14:23:36 -0700318std::pair<std::string, int32_t> AudioAnalytics::dump(
319 int32_t lines, int64_t sinceNs, const char *prefix) const
Andy Hung06f3aba2019-12-03 16:36:42 -0800320{
321 std::stringstream ss;
322 int32_t ll = lines;
323
324 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700325 auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700326 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800327 ll -= l;
328 }
329 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800330 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800331 --ll;
332 }
333 if (ll > 0) {
Andy Hung709b91e2020-04-04 14:23:36 -0700334 auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
Andy Hungb744faf2020-04-09 13:09:26 -0700335 ss << s;
Andy Hung06f3aba2019-12-03 16:36:42 -0800336 ll -= l;
337 }
Joey Poomarin52989982020-03-05 17:40:49 +0800338
Andy Hunga629bd12020-06-05 16:03:53 -0700339 if (ll > 0) {
340 // Print the statsd atoms we sent out.
341 const std::string statsd = mStatsdLog.dumpToString(" " /* prefix */, ll - 1);
342 const size_t n = std::count(statsd.begin(), statsd.end(), '\n') + 1; // we control this.
343 if ((size_t)ll >= n) {
344 if (n == 1) {
345 ss << "Statsd atoms: empty or truncated\n";
346 } else {
347 ss << "Statsd atoms:\n" << statsd;
348 }
349 ll -= n;
350 }
351 }
352
Joey Poomarin52989982020-03-05 17:40:49 +0800353 if (ll > 0 && prefix == nullptr) {
354 auto [s, l] = mAudioPowerUsage.dump(ll);
355 ss << s;
356 ll -= l;
357 }
Andy Hunga629bd12020-06-05 16:03:53 -0700358
Andy Hung06f3aba2019-12-03 16:36:42 -0800359 return { ss.str(), lines - ll };
360}
361
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800362void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
363{
364 auto actions = mActions.getActionsForItem(item); // internally locked.
365 // Execute actions with no lock held.
366 for (const auto& action : actions) {
367 (*action)(item);
368 }
369}
370
Andy Hungea186fa2020-01-09 18:13:15 -0800371// HELPER METHODS
372
373std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
374{
375 int32_t threadId_int32{};
376 if (mAnalyticsState->timeMachine().get(
377 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
378 return {};
379 }
380 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
381}
382
Andy Hungce9b6632020-04-28 20:15:17 -0700383// DeviceUse helper class.
384void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
Andy Hungea840382020-05-05 21:50:17 -0700385 const std::shared_ptr<const android::mediametrics::Item> &item, ItemType itemType) const {
Andy Hungce9b6632020-04-28 20:15:17 -0700386 const std::string& key = item->getKey();
387 const std::string id = key.substr(
Andy Hungea840382020-05-05 21:50:17 -0700388 (itemType == THREAD ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD)
389 : itemType == TRACK ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
390 : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD))
Andy Hungce9b6632020-04-28 20:15:17 -0700391 - 1);
392 // deliver statistics
393 int64_t deviceTimeNs = 0;
394 mAudioAnalytics.mAnalyticsState->timeMachine().get(
395 key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
396 std::string encoding;
397 mAudioAnalytics.mAnalyticsState->timeMachine().get(
398 key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
399 int32_t frameCount = 0;
400 mAudioAnalytics.mAnalyticsState->timeMachine().get(
401 key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700402 std::string inputDevicePairs;
Andy Hungea840382020-05-05 21:50:17 -0700403 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700404 key, AMEDIAMETRICS_PROP_INPUTDEVICES, &inputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700405 int32_t intervalCount = 0;
406 mAudioAnalytics.mAnalyticsState->timeMachine().get(
407 key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
Andy Hung1ea842e2020-05-18 10:47:31 -0700408 std::string outputDevicePairs;
Andy Hungce9b6632020-04-28 20:15:17 -0700409 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hung1ea842e2020-05-18 10:47:31 -0700410 key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevicePairs);
Andy Hungce9b6632020-04-28 20:15:17 -0700411 int32_t sampleRate = 0;
412 mAudioAnalytics.mAnalyticsState->timeMachine().get(
413 key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
Andy Hungea840382020-05-05 21:50:17 -0700414 std::string flags;
Andy Hungce9b6632020-04-28 20:15:17 -0700415 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hungea840382020-05-05 21:50:17 -0700416 key, AMEDIAMETRICS_PROP_FLAGS, &flags);
Andy Hung1ea842e2020-05-18 10:47:31 -0700417
Andy Hungea840382020-05-05 21:50:17 -0700418 // We may have several devices.
Andy Hung1ea842e2020-05-18 10:47:31 -0700419 // Accumulate the bit flags for input and output devices.
420 std::stringstream oss;
421 long_enum_type_t outputDeviceBits{};
422 { // compute outputDevices
423 const auto devaddrvec = stringutils::getDeviceAddressPairs(outputDevicePairs);
Andy Hungea840382020-05-05 21:50:17 -0700424 for (const auto& [device, addr] : devaddrvec) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700425 if (oss.tellp() > 0) oss << "|"; // delimit devices with '|'.
426 oss << device;
427 outputDeviceBits += types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(device);
Andy Hungea840382020-05-05 21:50:17 -0700428 }
429 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700430 const std::string outputDevices = oss.str();
431
432 std::stringstream iss;
433 long_enum_type_t inputDeviceBits{};
434 { // compute inputDevices
435 const auto devaddrvec = stringutils::getDeviceAddressPairs(inputDevicePairs);
436 for (const auto& [device, addr] : devaddrvec) {
437 if (iss.tellp() > 0) iss << "|"; // delimit devices with '|'.
438 iss << device;
439 inputDeviceBits += types::lookup<types::INPUT_DEVICE, long_enum_type_t>(device);
440 }
441 }
442 const std::string inputDevices = iss.str();
Andy Hungce9b6632020-04-28 20:15:17 -0700443
444 // Get connected device name if from bluetooth.
445 bool isBluetooth = false;
Andy Hunga629bd12020-06-05 16:03:53 -0700446
447 std::string inputDeviceNames; // not filled currently.
448 std::string outputDeviceNames;
Andy Hungce9b6632020-04-28 20:15:17 -0700449 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
450 isBluetooth = true;
451 mAudioAnalytics.mAnalyticsState->timeMachine().get(
Andy Hunga629bd12020-06-05 16:03:53 -0700452 "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &outputDeviceNames);
Andy Hung1ea842e2020-05-18 10:47:31 -0700453 // Remove | if present
Andy Hunga629bd12020-06-05 16:03:53 -0700454 stringutils::replace(outputDeviceNames, "|", '?');
455 if (outputDeviceNames.size() > STATSD_DEVICE_NAME_MAX_LENGTH) {
456 outputDeviceNames.resize(STATSD_DEVICE_NAME_MAX_LENGTH); // truncate
457 }
Andy Hungce9b6632020-04-28 20:15:17 -0700458 }
459
Andy Hungea840382020-05-05 21:50:17 -0700460 switch (itemType) {
461 case RECORD: {
462 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700463 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
464 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
Andy Hungce9b6632020-04-28 20:15:17 -0700465
Andy Hungea840382020-05-05 21:50:17 -0700466 std::string packageName;
467 int64_t versionCode = 0;
468 int32_t uid = -1;
469 mAudioAnalytics.mAnalyticsState->timeMachine().get(
470 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
471 if (uid != -1) {
472 std::tie(packageName, versionCode) =
473 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
474 }
475
476 int32_t selectedDeviceId = 0;
477 mAudioAnalytics.mAnalyticsState->timeMachine().get(
478 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
479 std::string source;
480 mAudioAnalytics.mAnalyticsState->timeMachine().get(
481 key, AMEDIAMETRICS_PROP_SOURCE, &source);
482
Andy Hung1ea842e2020-05-18 10:47:31 -0700483 const auto callerNameForStats =
484 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
485 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
486 const auto flagsForStats = types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags);
487 const auto sourceForStats = types::lookup<types::SOURCE_TYPE, short_enum_type_t>(source);
Andy Hungea840382020-05-05 21:50:17 -0700488
Andy Hunga629bd12020-06-05 16:03:53 -0700489 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700490 << " id:" << id
491 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700492 << ") inputDeviceNames:" << inputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700493 << " deviceTimeNs:" << deviceTimeNs
494 << " encoding:" << encoding << "(" << encodingForStats
495 << ") frameCount:" << frameCount
496 << " intervalCount:" << intervalCount
497 << " sampleRate:" << sampleRate
498 << " flags:" << flags << "(" << flagsForStats
499 << ") packageName:" << packageName
500 << " selectedDeviceId:" << selectedDeviceId
501 << " callerName:" << callerName << "(" << callerNameForStats
502 << ") source:" << source << "(" << sourceForStats << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700503 if (clientCalled // only log if client app called AudioRecord.
504 && mAudioAnalytics.mDeliverStatistics) {
505 const auto [ result, str ] = sendToStatsd(AudioRecordDeviceUsageFields,
506 CONDITION(android::util::MEDIAMETRICS_AUDIORECORDDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700507 , ENUM_EXTRACT(inputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700508 , inputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700509 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700510 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700511 , frameCount
512 , intervalCount
513 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700514 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700515
516 , packageName.c_str()
517 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700518 , ENUM_EXTRACT(callerNameForStats)
519 , ENUM_EXTRACT(sourceForStats)
Andy Hungea840382020-05-05 21:50:17 -0700520 );
Andy Hunga629bd12020-06-05 16:03:53 -0700521 ALOGV("%s: statsd %s", __func__, str.c_str());
522 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700523 }
Andy Hungea840382020-05-05 21:50:17 -0700524 } break;
525 case THREAD: {
526 std::string type;
527 mAudioAnalytics.mAnalyticsState->timeMachine().get(
528 key, AMEDIAMETRICS_PROP_TYPE, &type);
529 int32_t underrun = 0; // zero for record types
530 mAudioAnalytics.mAnalyticsState->timeMachine().get(
531 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hung1ea842e2020-05-18 10:47:31 -0700532
533 const bool isInput = types::isInputThreadType(type);
534 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
535 const auto flagsForStats =
536 (isInput ? types::lookup<types::INPUT_FLAG, short_enum_type_t>(flags)
537 : types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags));
538 const auto typeForStats = types::lookup<types::THREAD_TYPE, short_enum_type_t>(type);
539
Andy Hunga629bd12020-06-05 16:03:53 -0700540 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700541 << " id:" << id
542 << " inputDevices:" << inputDevices << "(" << inputDeviceBits
543 << ") outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700544 << ") inputDeviceNames:" << inputDeviceNames
545 << " outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700546 << " deviceTimeNs:" << deviceTimeNs
547 << " encoding:" << encoding << "(" << encodingForStats
548 << ") frameCount:" << frameCount
549 << " intervalCount:" << intervalCount
550 << " sampleRate:" << sampleRate
551 << " underrun:" << underrun
552 << " flags:" << flags << "(" << flagsForStats
553 << ") type:" << type << "(" << typeForStats
554 << ")";
Andy Hungea840382020-05-05 21:50:17 -0700555 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700556 const auto [ result, str ] = sendToStatsd(AudioThreadDeviceUsageFields,
557 CONDITION(android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED)
558 , isInput ? ENUM_EXTRACT(inputDeviceBits) : ENUM_EXTRACT(outputDeviceBits)
559 , isInput ? inputDeviceNames.c_str() : outputDeviceNames.c_str()
Andy Hungea840382020-05-05 21:50:17 -0700560 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700561 , ENUM_EXTRACT(encodingForStats)
Andy Hungea840382020-05-05 21:50:17 -0700562 , frameCount
563 , intervalCount
564 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700565 , ENUM_EXTRACT(flagsForStats)
Andy Hungea840382020-05-05 21:50:17 -0700566 , underrun
Andy Hung1ea842e2020-05-18 10:47:31 -0700567 , ENUM_EXTRACT(typeForStats)
Andy Hungea840382020-05-05 21:50:17 -0700568 );
Andy Hunga629bd12020-06-05 16:03:53 -0700569 ALOGV("%s: statsd %s", __func__, str.c_str());
570 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700571 }
Andy Hungea840382020-05-05 21:50:17 -0700572 } break;
573 case TRACK: {
Andy Hungce9b6632020-04-28 20:15:17 -0700574 std::string callerName;
Andy Hunga629bd12020-06-05 16:03:53 -0700575 const bool clientCalled = mAudioAnalytics.mAnalyticsState->timeMachine().get(
576 key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName) == OK;
577
Andy Hungce9b6632020-04-28 20:15:17 -0700578 std::string contentType;
579 mAudioAnalytics.mAnalyticsState->timeMachine().get(
580 key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
581 double deviceLatencyMs = 0.;
582 mAudioAnalytics.mAnalyticsState->timeMachine().get(
583 key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
584 double deviceStartupMs = 0.;
585 mAudioAnalytics.mAnalyticsState->timeMachine().get(
586 key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
587 double deviceVolume = 0.;
588 mAudioAnalytics.mAnalyticsState->timeMachine().get(
589 key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
590 std::string packageName;
591 int64_t versionCode = 0;
592 int32_t uid = -1;
593 mAudioAnalytics.mAnalyticsState->timeMachine().get(
594 key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
595 if (uid != -1) {
596 std::tie(packageName, versionCode) =
597 MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
598 }
599 double playbackPitch = 0.;
600 mAudioAnalytics.mAnalyticsState->timeMachine().get(
601 key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
602 double playbackSpeed = 0.;
603 mAudioAnalytics.mAnalyticsState->timeMachine().get(
604 key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
605 int32_t selectedDeviceId = 0;
606 mAudioAnalytics.mAnalyticsState->timeMachine().get(
607 key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
Andy Hungea840382020-05-05 21:50:17 -0700608 std::string streamType;
609 mAudioAnalytics.mAnalyticsState->timeMachine().get(
610 key, AMEDIAMETRICS_PROP_STREAMTYPE, &streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700611 std::string traits;
612 mAudioAnalytics.mAnalyticsState->timeMachine().get(
613 key, AMEDIAMETRICS_PROP_TRAITS, &traits);
Andy Hungea840382020-05-05 21:50:17 -0700614 int32_t underrun = 0;
615 mAudioAnalytics.mAnalyticsState->timeMachine().get(
616 key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
Andy Hungce9b6632020-04-28 20:15:17 -0700617 std::string usage;
618 mAudioAnalytics.mAnalyticsState->timeMachine().get(
619 key, AMEDIAMETRICS_PROP_USAGE, &usage);
620
Andy Hung1ea842e2020-05-18 10:47:31 -0700621 const auto callerNameForStats =
622 types::lookup<types::CALLER_NAME, short_enum_type_t>(callerName);
623 const auto contentTypeForStats =
624 types::lookup<types::CONTENT_TYPE, short_enum_type_t>(contentType);
625 const auto encodingForStats = types::lookup<types::ENCODING, short_enum_type_t>(encoding);
626 const auto flagsForStats = types::lookup<types::OUTPUT_FLAG, short_enum_type_t>(flags);
627 const auto streamTypeForStats =
628 types::lookup<types::STREAM_TYPE, short_enum_type_t>(streamType);
Andy Hunga629bd12020-06-05 16:03:53 -0700629 const auto traitsForStats =
630 types::lookup<types::TRACK_TRAITS, short_enum_type_t>(traits);
Andy Hung1ea842e2020-05-18 10:47:31 -0700631 const auto usageForStats = types::lookup<types::USAGE, short_enum_type_t>(usage);
632
Andy Hunga629bd12020-06-05 16:03:53 -0700633 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700634 << " id:" << id
635 << " outputDevices:" << outputDevices << "(" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700636 << ") outputDeviceNames:" << outputDeviceNames
Andy Hung1ea842e2020-05-18 10:47:31 -0700637 << " deviceTimeNs:" << deviceTimeNs
638 << " encoding:" << encoding << "(" << encodingForStats
639 << ") frameCount:" << frameCount
640 << " intervalCount:" << intervalCount
641 << " sampleRate:" << sampleRate
642 << " underrun:" << underrun
643 << " flags:" << flags << "(" << flagsForStats
644 << ") callerName:" << callerName << "(" << callerNameForStats
645 << ") contentType:" << contentType << "(" << contentTypeForStats
646 << ") deviceLatencyMs:" << deviceLatencyMs
647 << " deviceStartupMs:" << deviceStartupMs
648 << " deviceVolume:" << deviceVolume
649 << " packageName:" << packageName
650 << " playbackPitch:" << playbackPitch
651 << " playbackSpeed:" << playbackSpeed
652 << " selectedDeviceId:" << selectedDeviceId
653 << " streamType:" << streamType << "(" << streamTypeForStats
Andy Hunga629bd12020-06-05 16:03:53 -0700654 << ") traits:" << traits << "(" << traitsForStats
Andy Hung1ea842e2020-05-18 10:47:31 -0700655 << ") usage:" << usage << "(" << usageForStats
656 << ")";
Andy Hunga629bd12020-06-05 16:03:53 -0700657 if (clientCalled // only log if client app called AudioTracks
658 && mAudioAnalytics.mDeliverStatistics) {
659 const auto [ result, str ] = sendToStatsd(AudioTrackDeviceUsageFields,
660 CONDITION(android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700661 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700662 , outputDeviceNames.c_str()
Andy Hungce9b6632020-04-28 20:15:17 -0700663 , deviceTimeNs
Andy Hung1ea842e2020-05-18 10:47:31 -0700664 , ENUM_EXTRACT(encodingForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700665 , frameCount
666 , intervalCount
667 , sampleRate
Andy Hung1ea842e2020-05-18 10:47:31 -0700668 , ENUM_EXTRACT(flagsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700669 , underrun
Andy Hungce9b6632020-04-28 20:15:17 -0700670 , packageName.c_str()
671 , (float)deviceLatencyMs
672 , (float)deviceStartupMs
673 , (float)deviceVolume
674 , selectedDeviceId
Andy Hung1ea842e2020-05-18 10:47:31 -0700675 , ENUM_EXTRACT(streamTypeForStats)
676 , ENUM_EXTRACT(usageForStats)
677 , ENUM_EXTRACT(contentTypeForStats)
678 , ENUM_EXTRACT(callerNameForStats)
Andy Hunga629bd12020-06-05 16:03:53 -0700679 , ENUM_EXTRACT(traitsForStats)
Andy Hungce9b6632020-04-28 20:15:17 -0700680 );
Andy Hunga629bd12020-06-05 16:03:53 -0700681 ALOGV("%s: statsd %s", __func__, str.c_str());
682 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungce9b6632020-04-28 20:15:17 -0700683 }
Andy Hungea840382020-05-05 21:50:17 -0700684 } break;
Andy Hungce9b6632020-04-28 20:15:17 -0700685 }
686
687 // Report this as needed.
688 if (isBluetooth) {
689 // report this for Bluetooth
690 }
691}
692
693// DeviceConnection helper class.
694void AudioAnalytics::DeviceConnection::a2dpConnected(
695 const std::shared_ptr<const android::mediametrics::Item> &item) {
696 const std::string& key = item->getKey();
Andy Hungea840382020-05-05 21:50:17 -0700697 const int64_t atNs = item->getTimestamp();
Andy Hungce9b6632020-04-28 20:15:17 -0700698 {
699 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700700 mA2dpConnectionServiceNs = atNs;
701 ++mA2dpConnectionServices;
702
703 if (mA2dpConnectionRequestNs == 0) {
704 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
705 }
706 // This sets the time we were connected. Now we look for the delta in the future.
Andy Hungce9b6632020-04-28 20:15:17 -0700707 }
708 std::string name;
709 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700710 ALOGD("(key=%s) a2dp connected device:%s atNs:%lld",
711 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungce9b6632020-04-28 20:15:17 -0700712}
713
714void AudioAnalytics::DeviceConnection::createPatch(
715 const std::shared_ptr<const android::mediametrics::Item> &item) {
716 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700717 if (mA2dpConnectionServiceNs == 0) return; // patch unrelated to us.
Andy Hungce9b6632020-04-28 20:15:17 -0700718 const std::string& key = item->getKey();
719 std::string outputDevices;
720 item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
Andy Hungea840382020-05-05 21:50:17 -0700721 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH_A2DP") != std::string::npos) {
Andy Hungce9b6632020-04-28 20:15:17 -0700722 // TODO compare address
Andy Hung1ea842e2020-05-18 10:47:31 -0700723 int64_t timeDiffNs = item->getTimestamp();
Andy Hungea840382020-05-05 21:50:17 -0700724 if (mA2dpConnectionRequestNs == 0) {
725 ALOGD("%s: A2DP create patch didn't see a connection request", __func__);
Andy Hung1ea842e2020-05-18 10:47:31 -0700726 timeDiffNs -= mA2dpConnectionServiceNs;
Andy Hungea840382020-05-05 21:50:17 -0700727 } else {
Andy Hung1ea842e2020-05-18 10:47:31 -0700728 timeDiffNs -= mA2dpConnectionRequestNs;
Andy Hungea840382020-05-05 21:50:17 -0700729 }
Andy Hung1ea842e2020-05-18 10:47:31 -0700730
Andy Hungea840382020-05-05 21:50:17 -0700731 mA2dpConnectionRequestNs = 0;
732 mA2dpConnectionServiceNs = 0;
733 ++mA2dpConnectionSuccesses;
734
Andy Hung1ea842e2020-05-18 10:47:31 -0700735 const auto connectionTimeMs = float(timeDiffNs * 1e-6);
736
737 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
738 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
739
Andy Hunga629bd12020-06-05 16:03:53 -0700740 LOG(LOG_LEVEL) << "key:" << key
Andy Hung1ea842e2020-05-18 10:47:31 -0700741 << " A2DP SUCCESS"
742 << " outputDevices:" << outputDeviceBits
Andy Hunga629bd12020-06-05 16:03:53 -0700743 << " deviceName:" << mA2dpDeviceName
Andy Hung1ea842e2020-05-18 10:47:31 -0700744 << " connectionTimeMs:" << connectionTimeMs;
Andy Hungea840382020-05-05 21:50:17 -0700745 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hung1ea842e2020-05-18 10:47:31 -0700746 const long_enum_type_t inputDeviceBits{};
Andy Hunga629bd12020-06-05 16:03:53 -0700747
748 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
749 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700750 , ENUM_EXTRACT(inputDeviceBits)
751 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700752 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700753 , types::DEVICE_CONNECTION_RESULT_SUCCESS
754 , connectionTimeMs
Andy Hungea840382020-05-05 21:50:17 -0700755 , /* connection_count */ 1
756 );
Andy Hunga629bd12020-06-05 16:03:53 -0700757 ALOGV("%s: statsd %s", __func__, str.c_str());
758 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700759 }
Andy Hungce9b6632020-04-28 20:15:17 -0700760 }
761}
762
Andy Hungea840382020-05-05 21:50:17 -0700763// Called through AudioManager when the BT service wants to enable
764void AudioAnalytics::DeviceConnection::postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
765 const std::shared_ptr<const android::mediametrics::Item> &item) {
766 const int64_t atNs = item->getTimestamp();
767 const std::string& key = item->getKey();
768 std::string state;
769 item->get(AMEDIAMETRICS_PROP_STATE, &state);
770 if (state != "connected") return;
Andy Hunga629bd12020-06-05 16:03:53 -0700771
772 std::string name;
773 item->get(AMEDIAMETRICS_PROP_NAME, &name);
Andy Hungea840382020-05-05 21:50:17 -0700774 {
775 std::lock_guard l(mLock);
776 mA2dpConnectionRequestNs = atNs;
777 ++mA2dpConnectionRequests;
Andy Hunga629bd12020-06-05 16:03:53 -0700778 mA2dpDeviceName = name;
Andy Hungea840382020-05-05 21:50:17 -0700779 }
Andy Hunga629bd12020-06-05 16:03:53 -0700780 ALOGD("(key=%s) a2dp connection name:%s request atNs:%lld",
781 key.c_str(), name.c_str(), (long long)atNs);
Andy Hungea840382020-05-05 21:50:17 -0700782 // TODO: attempt to cancel a timed event, rather than let it expire.
783 mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
784}
785
Andy Hungce9b6632020-04-28 20:15:17 -0700786void AudioAnalytics::DeviceConnection::expire() {
787 std::lock_guard l(mLock);
Andy Hungea840382020-05-05 21:50:17 -0700788 if (mA2dpConnectionRequestNs == 0) return; // ignore (this was an internal connection).
Andy Hung1ea842e2020-05-18 10:47:31 -0700789
Andy Hung1ea842e2020-05-18 10:47:31 -0700790 const long_enum_type_t inputDeviceBits{};
Andy Hung1ea842e2020-05-18 10:47:31 -0700791 const auto outputDeviceBits = types::lookup<types::OUTPUT_DEVICE, long_enum_type_t>(
792 "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP");
793
Andy Hungea840382020-05-05 21:50:17 -0700794 if (mA2dpConnectionServiceNs == 0) {
Andy Hungea840382020-05-05 21:50:17 -0700795 ++mA2dpConnectionJavaServiceCancels; // service did not connect to A2DP
Andy Hungce9b6632020-04-28 20:15:17 -0700796
Andy Hunga629bd12020-06-05 16:03:53 -0700797 LOG(LOG_LEVEL) << "A2DP CANCEL"
798 << " outputDevices:" << outputDeviceBits
799 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700800 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700801 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
802 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700803 , ENUM_EXTRACT(inputDeviceBits)
804 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700805 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700806 , types::DEVICE_CONNECTION_RESULT_JAVA_SERVICE_CANCEL
Andy Hungea840382020-05-05 21:50:17 -0700807 , /* connection_time_ms */ 0.f
808 , /* connection_count */ 1
809 );
Andy Hunga629bd12020-06-05 16:03:53 -0700810 ALOGV("%s: statsd %s", __func__, str.c_str());
811 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700812 }
Andy Hungea840382020-05-05 21:50:17 -0700813 return;
814 }
815
816 // AudioFlinger didn't play - an expiration may occur because there is no audio playing.
817 // Should we check elsewhere?
Andy Hungce9b6632020-04-28 20:15:17 -0700818 // TODO: disambiguate this case.
Andy Hungea840382020-05-05 21:50:17 -0700819 mA2dpConnectionRequestNs = 0;
820 mA2dpConnectionServiceNs = 0;
821 ++mA2dpConnectionUnknowns; // connection result unknown
Andy Hung1ea842e2020-05-18 10:47:31 -0700822
Andy Hunga629bd12020-06-05 16:03:53 -0700823 LOG(LOG_LEVEL) << "A2DP UNKNOWN"
824 << " outputDevices:" << outputDeviceBits
825 << " deviceName:" << mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700826 if (mAudioAnalytics.mDeliverStatistics) {
Andy Hunga629bd12020-06-05 16:03:53 -0700827 const auto [ result, str ] = sendToStatsd(AudioDeviceConnectionFields,
828 CONDITION(android::util::MEDIAMETRICS_AUDIODEVICECONNECTION_REPORTED)
Andy Hung1ea842e2020-05-18 10:47:31 -0700829 , ENUM_EXTRACT(inputDeviceBits)
830 , ENUM_EXTRACT(outputDeviceBits)
Andy Hunga629bd12020-06-05 16:03:53 -0700831 , mA2dpDeviceName.c_str()
Andy Hung1ea842e2020-05-18 10:47:31 -0700832 , types::DEVICE_CONNECTION_RESULT_UNKNOWN
Andy Hungea840382020-05-05 21:50:17 -0700833 , /* connection_time_ms */ 0.f
834 , /* connection_count */ 1
835 );
Andy Hunga629bd12020-06-05 16:03:53 -0700836 ALOGV("%s: statsd %s", __func__, str.c_str());
837 mAudioAnalytics.mStatsdLog.log("%s", str.c_str());
Andy Hungea840382020-05-05 21:50:17 -0700838 }
Andy Hungce9b6632020-04-28 20:15:17 -0700839}
840
Andy Hung3ab1b322020-05-18 10:47:31 -0700841} // namespace android::mediametrics