blob: f3425dfe13a6bc5cee9cf7cfdcc7cde43d8d7f18 [file] [log] [blame]
Andy Hungc2b11cb2020-04-22 09:04:01 -07001/*
2 * Copyright (C) 2020 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#ifndef ANDROID_AUDIO_TRACKMETRICS_H
18#define ANDROID_AUDIO_TRACKMETRICS_H
19
Kunal Malhotra3be68902023-02-28 22:03:15 +000020#include <binder/IActivityManager.h>
21#include <binder/IPCThreadState.h>
22#include <binder/IServiceManager.h>
Andy Hungc2b11cb2020-04-22 09:04:01 -070023#include <mutex>
24
25namespace android {
26
27/**
28 * TrackMetrics handles the AudioFlinger track metrics.
29 *
30 * We aggregate metrics for a particular device for proper analysis.
31 * This includes power, performance, and usage metrics.
32 *
33 * This class is thread-safe with a lock for safety. There is no risk of deadlock
34 * as this class only executes external one-way calls in Mediametrics and does not
35 * call any other AudioFlinger class.
36 *
37 * Terminology:
38 * An AudioInterval is a contiguous playback segment.
39 * An AudioIntervalGroup is a group of continuous playback segments on the same device.
40 *
41 * We currently deliver metrics based on an AudioIntervalGroup.
42 */
43class TrackMetrics final {
Kunal Malhotra3be68902023-02-28 22:03:15 +000044
45
Andy Hungc2b11cb2020-04-22 09:04:01 -070046public:
Kunal Malhotra3be68902023-02-28 22:03:15 +000047 TrackMetrics(std::string metricsId, bool isOut, int clientUid)
Andy Hungc2b11cb2020-04-22 09:04:01 -070048 : mMetricsId(std::move(metricsId))
49 , mIsOut(isOut)
Kunal Malhotra3be68902023-02-28 22:03:15 +000050 , mUid(clientUid)
Andy Hungc2b11cb2020-04-22 09:04:01 -070051 {} // we don't log a constructor item, we wait for more info in logConstructor().
52
53 ~TrackMetrics() {
54 logEndInterval();
55 std::lock_guard l(mLock);
56 deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
57 // we don't log a destructor item here.
58 }
59
60 // Called under the following circumstances
61 // 1) when we are added to the Thread
62 // 2) when we have a createPatch in the Thread.
63 void logBeginInterval(const std::string& devices) {
64 std::lock_guard l(mLock);
65 if (mDevices != devices) {
66 deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
67 mDevices = devices;
68 resetIntervalGroupMetrics();
69 deliverDeviceMetrics(
70 AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, devices.c_str());
71 }
72 ++mIntervalCount;
Kunal Malhotra3be68902023-02-28 22:03:15 +000073 const auto& mActivityManager = getActivityManager();
74 if (mActivityManager) {
Kunal Malhotraae6d1602023-03-30 00:17:25 +000075 if (mIsOut) {
76 mActivityManager->logFgsApiBegin(AUDIO_API,
77 mUid,
78 IPCThreadState::self() -> getCallingPid());
79 } else {
80 mActivityManager->logFgsApiBegin(MICROPHONE_API,
81 mUid,
82 IPCThreadState::self() -> getCallingPid());
83 }
Kunal Malhotra3be68902023-02-28 22:03:15 +000084 }
Andy Hungc2b11cb2020-04-22 09:04:01 -070085 }
86
Andy Hung5837c7f2021-02-25 10:48:24 -080087 void logConstructor(pid_t creatorPid, uid_t creatorUid, int32_t internalTrackId,
Andy Hunga629bd12020-06-05 16:03:53 -070088 const std::string& traits = {},
Andy Hungea840382020-05-05 21:50:17 -070089 audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT) const {
Andy Hungc2b11cb2020-04-22 09:04:01 -070090 // Once this item is logged by the server, the client can add properties.
91 // no lock required, all local or const variables.
Andy Hungea840382020-05-05 21:50:17 -070092 mediametrics::LogItem item(mMetricsId);
93 item.setPid(creatorPid)
Andy Hungc2b11cb2020-04-22 09:04:01 -070094 .setUid(creatorUid)
95 .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
96 .set(AMEDIAMETRICS_PROP_EVENT,
Andy Hunga629bd12020-06-05 16:03:53 -070097 AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
Andy Hung5837c7f2021-02-25 10:48:24 -080098 .set(AMEDIAMETRICS_PROP_INTERNALTRACKID, internalTrackId)
Andy Hunga629bd12020-06-05 16:03:53 -070099 .set(AMEDIAMETRICS_PROP_TRAITS, traits);
Andy Hungea840382020-05-05 21:50:17 -0700100 // log streamType from the service, since client doesn't know chosen streamType.
101 if (streamType != AUDIO_STREAM_DEFAULT) {
102 item.set(AMEDIAMETRICS_PROP_STREAMTYPE, toString(streamType).c_str());
103 }
104 item.record();
Andy Hungc2b11cb2020-04-22 09:04:01 -0700105 }
106
107 // Called when we are removed from the Thread.
108 void logEndInterval() {
109 std::lock_guard l(mLock);
Andy Hunga81a4b42022-05-19 19:24:51 -0700110 if (mLastVolumeChangeTimeNs != 0) {
111 logVolume_l(mVolume); // flush out the last volume.
112 mLastVolumeChangeTimeNs = 0;
Andy Hungc2b11cb2020-04-22 09:04:01 -0700113 }
Kunal Malhotra3be68902023-02-28 22:03:15 +0000114 const auto& mActivityManager = getActivityManager();
115 if (mActivityManager) {
Kunal Malhotraae6d1602023-03-30 00:17:25 +0000116 if (mIsOut) {
117 mActivityManager->logFgsApiEnd(AUDIO_API,
118 mUid,
119 IPCThreadState::self() -> getCallingPid());
120 } else {
121 mActivityManager->logFgsApiEnd(MICROPHONE_API,
122 mUid,
123 IPCThreadState::self() -> getCallingPid());
124 }
Kunal Malhotra3be68902023-02-28 22:03:15 +0000125 }
Andy Hungc2b11cb2020-04-22 09:04:01 -0700126 }
127
128 void logInvalidate() const {
129 // no lock required, all local or const variables.
130 mediametrics::LogItem(mMetricsId)
131 .set(AMEDIAMETRICS_PROP_EVENT,
132 AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
133 .record();
134 }
135
136 void logLatencyAndStartup(double latencyMs, double startupMs) {
137 mediametrics::LogItem(mMetricsId)
138 .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
139 .set(AMEDIAMETRICS_PROP_STARTUPMS, startupMs)
140 .record();
141 std::lock_guard l(mLock);
142 mDeviceLatencyMs.add(latencyMs);
143 mDeviceStartupMs.add(startupMs);
144 }
145
Andy Hung920f6572022-10-06 12:09:49 -0700146 void updateMinMaxVolume_l(int64_t durationNs, double deviceVolume)
147 REQUIRES(mLock) {
Robert Lee36ac0412022-01-13 03:05:41 +0000148 if (deviceVolume > mMaxVolume) {
149 mMaxVolume = deviceVolume;
150 mMaxVolumeDurationNs = durationNs;
151 } else if (deviceVolume == mMaxVolume) {
152 mMaxVolumeDurationNs += durationNs;
153 }
154 if (deviceVolume < mMinVolume) {
155 mMinVolume = deviceVolume;
156 mMinVolumeDurationNs = durationNs;
157 } else if (deviceVolume == mMinVolume) {
158 mMinVolumeDurationNs += durationNs;
159 }
160 }
161
Andy Hungc2b11cb2020-04-22 09:04:01 -0700162 // may be called multiple times during an interval
163 void logVolume(float volume) {
Andy Hungc2b11cb2020-04-22 09:04:01 -0700164 std::lock_guard l(mLock);
Andy Hunga81a4b42022-05-19 19:24:51 -0700165 logVolume_l(volume);
Andy Hungc2b11cb2020-04-22 09:04:01 -0700166 }
167
168 // Use absolute numbers returned by AudioTrackShared.
169 void logUnderruns(size_t count, size_t frames) {
170 std::lock_guard l(mLock);
171 mUnderrunCount = count;
172 mUnderrunFrames = frames;
173 // Consider delivering a message here (also be aware of excessive spam).
174 }
175
176private:
Andy Hunga81a4b42022-05-19 19:24:51 -0700177
Andy Hungc2b11cb2020-04-22 09:04:01 -0700178 // no lock required - all arguments and constants.
179 void deliverDeviceMetrics(const char *eventName, const char *devices) const {
180 mediametrics::LogItem(mMetricsId)
181 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
182 .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
183 : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
184 .record();
185 }
186
Andy Hunga81a4b42022-05-19 19:24:51 -0700187 void logVolume_l(float volume) REQUIRES(mLock) {
188 const int64_t timeNs = systemTime();
189 const int64_t durationNs = mLastVolumeChangeTimeNs == 0
190 ? 0 : timeNs - mLastVolumeChangeTimeNs;
191 if (durationNs > 0) {
192 // See West's algorithm for weighted averages
193 // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
194 mDeviceVolume += (mVolume - mDeviceVolume) * durationNs
195 / (durationNs + mDeviceTimeNs);
196 mDeviceTimeNs += durationNs;
197 mCumulativeTimeNs += durationNs;
198 }
Andy Hung920f6572022-10-06 12:09:49 -0700199 updateMinMaxVolume_l(durationNs, mVolume); // always update.
Andy Hunga81a4b42022-05-19 19:24:51 -0700200 mVolume = volume;
201 mLastVolumeChangeTimeNs = timeNs;
202 }
203
Andy Hungc2b11cb2020-04-22 09:04:01 -0700204 void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
205 if (mIntervalCount > 0) {
206 mediametrics::LogItem item(mMetricsId);
207 item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
208 .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
209 .set(AMEDIAMETRICS_PROP_EVENT, eventName)
210 .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
211 if (mIsOut) {
Robert Lee36ac0412022-01-13 03:05:41 +0000212 item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume)
213 .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUMEDURATIONNS, mMaxVolumeDurationNs)
214 .set(AMEDIAMETRICS_PROP_DEVICEMAXVOLUME, mMaxVolume)
215 .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUMEDURATIONNS, mMinVolumeDurationNs)
216 .set(AMEDIAMETRICS_PROP_DEVICEMINVOLUME, mMinVolume);
Andy Hungc2b11cb2020-04-22 09:04:01 -0700217 }
218 if (mDeviceLatencyMs.getN() > 0) {
219 item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
220 .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
221 }
222 if (mUnderrunCount > 0) {
223 item.set(AMEDIAMETRICS_PROP_UNDERRUN,
224 (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
225 .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
226 (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
227 }
228 item.record();
229 }
230 }
231
232 void resetIntervalGroupMetrics() REQUIRES(mLock) {
233 // mDevices is not reset by resetIntervalGroupMetrics.
234
235 mIntervalCount = 0;
Andy Hungc2b11cb2020-04-22 09:04:01 -0700236 // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
237 mDeviceTimeNs = 0;
238
239 mVolume = 0.f;
240 mDeviceVolume = 0.f;
Andy Hunga81a4b42022-05-19 19:24:51 -0700241 mLastVolumeChangeTimeNs = 0; // last time volume logged, cleared on endInterval
Robert Lee36ac0412022-01-13 03:05:41 +0000242 mMinVolume = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
243 mMaxVolume = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
244 mMinVolumeDurationNs = 0;
245 mMaxVolumeDurationNs = 0;
Andy Hungc2b11cb2020-04-22 09:04:01 -0700246
247 mDeviceLatencyMs.reset();
248 mDeviceStartupMs.reset();
249
250 mUnderrunCountSinceIntervalGroup = mUnderrunCount;
251 mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
252 // do not reset mUnderrunCount - it keeps continuously running for tracks.
253 }
254
Kunal Malhotra3be68902023-02-28 22:03:15 +0000255 // Meyer's singleton is thread-safe.
256 static const sp<IActivityManager>& getActivityManager() {
257 static const auto activityManager = []() -> sp<IActivityManager> {
258 const sp<IServiceManager> sm(defaultServiceManager());
259 if (sm != nullptr) {
260 return interface_cast<IActivityManager>(sm->checkService(String16("activity")));
261 }
262 return nullptr;
263 }();
264 return activityManager;
265 }
266
Andy Hungc2b11cb2020-04-22 09:04:01 -0700267 const std::string mMetricsId;
268 const bool mIsOut; // if true, than a playback track, otherwise used for record.
269
Kunal Malhotra3be68902023-02-28 22:03:15 +0000270 static constexpr int AUDIO_API = 5;
Kunal Malhotraae6d1602023-03-30 00:17:25 +0000271 static constexpr int MICROPHONE_API = 6;
Kunal Malhotra3be68902023-02-28 22:03:15 +0000272 const int mUid;
273
Andy Hungc2b11cb2020-04-22 09:04:01 -0700274 mutable std::mutex mLock;
275
276 // Devices in the interval group.
277 std::string mDevices GUARDED_BY(mLock);
278
279 // Number of intervals and playing time
280 int32_t mIntervalCount GUARDED_BY(mLock) = 0;
Andy Hunga81a4b42022-05-19 19:24:51 -0700281 int64_t mCumulativeTimeNs GUARDED_BY(mLock) = 0; // total time.
282 int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0; // time on device.
Andy Hungc2b11cb2020-04-22 09:04:01 -0700283
284 // Average volume
Andy Hunga81a4b42022-05-19 19:24:51 -0700285 double mVolume GUARDED_BY(mLock) = 0.f; // last set volume.
286 double mDeviceVolume GUARDED_BY(mLock) = 0.f; // running average volume.
Andy Hungc2b11cb2020-04-22 09:04:01 -0700287 int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
288
Robert Lee36ac0412022-01-13 03:05:41 +0000289 // Min/Max volume
290 double mMinVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MIN_VOLUME;
291 double mMaxVolume GUARDED_BY(mLock) = AMEDIAMETRICS_INITIAL_MAX_VOLUME;
292 int64_t mMinVolumeDurationNs GUARDED_BY(mLock) = 0;
293 int64_t mMaxVolumeDurationNs GUARDED_BY(mLock) = 0;
294
Andy Hungc2b11cb2020-04-22 09:04:01 -0700295 // latency and startup for each interval.
296 audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
297 audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
298
299 // underrun count and frames
300 int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
301 int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
302 int64_t mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
303 int64_t mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
304};
305
306} // namespace android
307
308#endif // ANDROID_AUDIO_TRACKMETRICS_H