blob: 126e5012385d7b44466a93086d46223d6c3fa2f5 [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"
19#include <utils/Log.h>
20
21#include "AudioAnalytics.h"
22
23#include <audio_utils/clock.h> // clock conversions
24
25namespace android::mediametrics {
26
27AudioAnalytics::AudioAnalytics()
28{
29 ALOGD("%s", __func__);
Andy Hung0f7ad8c2020-01-03 13:24:34 -080030
31 // Add action to save AnalyticsState if audioserver is restarted.
32 // This triggers on an item of "audio.flinger"
33 // with a property "event" set to "AudioFlinger" (the constructor).
34 mActions.addAction(
Andy Hungea186fa2020-01-09 18:13:15 -080035 AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT,
36 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR),
Andy Hung0f7ad8c2020-01-03 13:24:34 -080037 std::make_shared<AnalyticsActions::Function>(
Andy Hungea186fa2020-01-09 18:13:15 -080038 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
39 ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str());
Andy Hung0f7ad8c2020-01-03 13:24:34 -080040 mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>(
41 *mAnalyticsState.get()));
42 // Note: get returns shared_ptr temp, whose lifetime is extended
43 // to end of full expression.
44 mAnalyticsState->clear(); // TODO: filter the analytics state.
Andy Hungea186fa2020-01-09 18:13:15 -080045 // Perhaps report this.
46 }));
47
48 // Check underruns
49 mActions.addAction(
50 AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
51 std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN),
52 std::make_shared<AnalyticsActions::Function>(
53 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
54 std::string threadId = item->getKey().substr(
55 sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) - 1);
56 std::string outputDevices;
57 mAnalyticsState->timeMachine().get(
58 item->getKey(), AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
59 ALOGD("(key=%s) Thread underrun event detected on io handle:%s device:%s",
60 item->getKey().c_str(), threadId.c_str(), outputDevices.c_str());
61 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
62 // report this for Bluetooth
63 }
64 }));
65
66 // Check latencies, playback and startup
67 mActions.addAction(
68 AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_LATENCYMS,
69 std::monostate{}, // accept any value
70 std::make_shared<AnalyticsActions::Function>(
71 [this](const std::shared_ptr<const android::mediametrics::Item> &item){
72 double latencyMs{};
73 double startupMs{};
74 if (!item->get(AMEDIAMETRICS_PROP_LATENCYMS, &latencyMs)
75 || !item->get(AMEDIAMETRICS_PROP_STARTUPMS, &startupMs)) return;
76
77 std::string trackId = item->getKey().substr(
78 sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) - 1);
79 std::string thread = getThreadFromTrack(item->getKey());
80 std::string outputDevices;
81 mAnalyticsState->timeMachine().get(
82 thread, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
83 ALOGD("(key=%s) Track latencyMs:%lf startupMs:%lf detected on port:%s device:%s",
84 item->getKey().c_str(), latencyMs, startupMs,
85 trackId.c_str(), outputDevices.c_str());
86 if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
87 // report this for Bluetooth
88 }
Andy Hung0f7ad8c2020-01-03 13:24:34 -080089 }));
Andy Hung06f3aba2019-12-03 16:36:42 -080090}
91
92AudioAnalytics::~AudioAnalytics()
93{
94 ALOGD("%s", __func__);
95}
96
97status_t AudioAnalytics::submit(
Ray Essickf27e9872019-12-07 06:28:46 -080098 const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted)
Andy Hung06f3aba2019-12-03 16:36:42 -080099{
Andy Hungea186fa2020-01-09 18:13:15 -0800100 if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE;
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800101 status_t status = mAnalyticsState->submit(item, isTrusted);
102 if (status != NO_ERROR) return status; // may not be permitted.
103
104 // Only if the item was successfully submitted (permission)
105 // do we check triggered actions.
106 checkActions(item);
107 return NO_ERROR;
Andy Hung06f3aba2019-12-03 16:36:42 -0800108}
109
110std::pair<std::string, int32_t> AudioAnalytics::dump(int32_t lines) const
111{
112 std::stringstream ss;
113 int32_t ll = lines;
114
115 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800116 auto [s, l] = mAnalyticsState->dump(ll);
Andy Hung06f3aba2019-12-03 16:36:42 -0800117 ss << s;
118 ll -= l;
119 }
120 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800121 ss << "Prior audioserver state:\n";
Andy Hung06f3aba2019-12-03 16:36:42 -0800122 --ll;
123 }
124 if (ll > 0) {
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800125 auto [s, l] = mPreviousAnalyticsState->dump(ll);
Andy Hung06f3aba2019-12-03 16:36:42 -0800126 ss << s;
127 ll -= l;
128 }
129 return { ss.str(), lines - ll };
130}
131
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800132void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item>& item)
133{
134 auto actions = mActions.getActionsForItem(item); // internally locked.
135 // Execute actions with no lock held.
136 for (const auto& action : actions) {
137 (*action)(item);
138 }
139}
140
Andy Hungea186fa2020-01-09 18:13:15 -0800141// HELPER METHODS
142
143std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const
144{
145 int32_t threadId_int32{};
146 if (mAnalyticsState->timeMachine().get(
147 track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) {
148 return {};
149 }
150 return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
151}
152
Andy Hung06f3aba2019-12-03 16:36:42 -0800153} // namespace android