blob: 2b41a95956c97522de5875cd3bf31ff9589e5ac9 [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#pragma once
18
Andy Hungce9b6632020-04-28 20:15:17 -070019#include <android-base/thread_annotations.h>
Andy Hung0f7ad8c2020-01-03 13:24:34 -080020#include "AnalyticsActions.h"
21#include "AnalyticsState.h"
Joey Poomarin52989982020-03-05 17:40:49 +080022#include "AudioPowerUsage.h"
Andy Hung5be90c82021-03-30 14:30:20 -070023#include "StatsdLog.h"
Andy Hungce9b6632020-04-28 20:15:17 -070024#include "TimedAction.h"
Andy Hung0f7ad8c2020-01-03 13:24:34 -080025#include "Wrap.h"
Andy Hung06f3aba2019-12-03 16:36:42 -080026
27namespace android::mediametrics {
28
29class AudioAnalytics
30{
Joey Poomarin52989982020-03-05 17:40:49 +080031 // AudioAnalytics action / state helper classes
32 friend AudioPowerUsage;
33
Andy Hung06f3aba2019-12-03 16:36:42 -080034public:
Andy Hung5be90c82021-03-30 14:30:20 -070035 explicit AudioAnalytics(const std::shared_ptr<StatsdLog>& statsdLog);
Andy Hung06f3aba2019-12-03 16:36:42 -080036 ~AudioAnalytics();
37
Andy Hung06f3aba2019-12-03 16:36:42 -080038 /**
39 * Returns success if AudioAnalytics recognizes item.
40 *
41 * AudioAnalytics requires the item key to start with "audio.".
42 *
43 * A trusted source can create a new key, an untrusted source
44 * can only modify the key if the uid will match that authorized
45 * on the existing key.
46 *
47 * \param item the item to be submitted.
48 * \param isTrusted whether the transaction comes from a trusted source.
49 * In this case, a trusted source is verified by binder
50 * UID to be a system service by MediaMetrics service.
51 * Do not use true if you haven't really checked!
Andy Hung0f7ad8c2020-01-03 13:24:34 -080052 *
53 * \return NO_ERROR on success,
54 * PERMISSION_DENIED if the item cannot be put into the AnalyticsState,
55 * BAD_VALUE if the item key does not start with "audio.".
Andy Hung06f3aba2019-12-03 16:36:42 -080056 */
Ray Essickf27e9872019-12-07 06:28:46 -080057 status_t submit(const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted);
Andy Hung06f3aba2019-12-03 16:36:42 -080058
59 /**
60 * Returns a pair consisting of the dump string, and the number of lines in the string.
61 *
62 * The number of lines in the returned pair is used as an optimization
63 * for subsequent line limiting.
64 *
65 * The TimeMachine and the TransactionLog are dumped separately under
66 * different locks, so may not be 100% consistent with the last data
67 * delivered.
68 *
69 * \param lines the maximum number of lines in the string returned.
Andy Hung709b91e2020-04-04 14:23:36 -070070 * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
71 * \param prefix the desired key prefix to match (nullptr shows all)
Andy Hung06f3aba2019-12-03 16:36:42 -080072 */
Andy Hung709b91e2020-04-04 14:23:36 -070073 std::pair<std::string, int32_t> dump(
74 int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const;
75
76 void clear() {
77 // underlying state is locked.
78 mPreviousAnalyticsState->clear();
79 mAnalyticsState->clear();
Joey Poomarin52989982020-03-05 17:40:49 +080080
81 // Clear power usage state.
82 mAudioPowerUsage.clear();
Andy Hung709b91e2020-04-04 14:23:36 -070083 }
Andy Hung06f3aba2019-12-03 16:36:42 -080084
85private:
Andy Hung0f7ad8c2020-01-03 13:24:34 -080086
Andy Hungea840382020-05-05 21:50:17 -070087 /*
88 * AudioAnalytics class does not contain a monitor mutex.
89 * Instead, all of its variables are individually locked for access.
90 * Since data and items are generally added only (gc removes it), this is a reasonable
91 * compromise for availability/concurrency versus consistency.
92 *
93 * It is possible for concurrent threads to be reading and writing inside of AudioAnalytics.
94 * Reads based on a prior time (e.g. one second) in the past from the TimeMachine can be
95 * used to achieve better consistency if needed.
96 */
97
Andy Hung0f7ad8c2020-01-03 13:24:34 -080098 /**
99 * Checks for any pending actions for a particular item.
100 *
101 * \param item to check against the current AnalyticsActions.
102 */
103 void checkActions(const std::shared_ptr<const mediametrics::Item>& item);
104
Andy Hungea186fa2020-01-09 18:13:15 -0800105 // HELPER METHODS
106 /**
107 * Return the audio thread associated with an audio track name.
108 * e.g. "audio.track.32" -> "audio.thread.10" if the associated
109 * threadId for the audio track is 10.
110 */
111 std::string getThreadFromTrack(const std::string& track) const;
112
Andy Hung1ea842e2020-05-18 10:47:31 -0700113 const bool mDeliverStatistics;
Andy Hungce9b6632020-04-28 20:15:17 -0700114
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800115 // Actions is individually locked
116 AnalyticsActions mActions;
117
118 // AnalyticsState is individually locked, and we use SharedPtrWrap
119 // to allow safe access even if the shared pointer changes underneath.
Andy Hungb18f5062020-06-18 23:10:08 -0700120 // These wrap pointers always point to a valid state object.
Andy Hung0f7ad8c2020-01-03 13:24:34 -0800121 SharedPtrWrap<AnalyticsState> mAnalyticsState;
122 SharedPtrWrap<AnalyticsState> mPreviousAnalyticsState;
Andy Hungce9b6632020-04-28 20:15:17 -0700123
124 TimedAction mTimedAction; // locked internally
Andy Hung5be90c82021-03-30 14:30:20 -0700125 const std::shared_ptr<StatsdLog> mStatsdLog; // locked internally, ok for multiple threads.
Andy Hunga629bd12020-06-05 16:03:53 -0700126
Andy Hungce9b6632020-04-28 20:15:17 -0700127 // DeviceUse is a nested class which handles audio device usage accounting.
128 // We define this class at the end to ensure prior variables all properly constructed.
129 // TODO: Track / Thread interaction
130 // TODO: Consider statistics aggregation.
131 class DeviceUse {
132 public:
Andy Hungea840382020-05-05 21:50:17 -0700133 enum ItemType {
134 RECORD = 0,
135 THREAD = 1,
136 TRACK = 2,
137 };
138
Andy Hungce9b6632020-04-28 20:15:17 -0700139 explicit DeviceUse(AudioAnalytics &audioAnalytics) : mAudioAnalytics{audioAnalytics} {}
140
141 // Called every time an endAudioIntervalGroup message is received.
142 void endAudioIntervalGroup(
143 const std::shared_ptr<const android::mediametrics::Item> &item,
Andy Hungea840382020-05-05 21:50:17 -0700144 ItemType itemType) const;
145
Andy Hungce9b6632020-04-28 20:15:17 -0700146 private:
147 AudioAnalytics &mAudioAnalytics;
148 } mDeviceUse{*this};
149
150 // DeviceConnected is a nested class which handles audio device connection
151 // We define this class at the end to ensure prior variables all properly constructed.
152 // TODO: Track / Thread interaction
153 // TODO: Consider statistics aggregation.
154 class DeviceConnection {
155 public:
156 explicit DeviceConnection(AudioAnalytics &audioAnalytics)
157 : mAudioAnalytics{audioAnalytics} {}
158
159 // Called every time an endAudioIntervalGroup message is received.
160 void a2dpConnected(
161 const std::shared_ptr<const android::mediametrics::Item> &item);
162
163 // Called when we have an AudioFlinger createPatch
164 void createPatch(
165 const std::shared_ptr<const android::mediametrics::Item> &item);
166
Andy Hungea840382020-05-05 21:50:17 -0700167 // Called through AudioManager when the BT service wants to notify connection
168 void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
169 const std::shared_ptr<const android::mediametrics::Item> &item);
170
Andy Hungce9b6632020-04-28 20:15:17 -0700171 // When the timer expires.
172 void expire();
173
174 private:
175 AudioAnalytics &mAudioAnalytics;
176
177 mutable std::mutex mLock;
Andy Hunga629bd12020-06-05 16:03:53 -0700178 std::string mA2dpDeviceName;
Andy Hungea840382020-05-05 21:50:17 -0700179 int64_t mA2dpConnectionRequestNs GUARDED_BY(mLock) = 0; // Time for BT service request.
180 int64_t mA2dpConnectionServiceNs GUARDED_BY(mLock) = 0; // Time audio service agrees.
181
182 int32_t mA2dpConnectionRequests GUARDED_BY(mLock) = 0;
183 int32_t mA2dpConnectionServices GUARDED_BY(mLock) = 0;
184
185 // See the statsd atoms.proto
186 int32_t mA2dpConnectionSuccesses GUARDED_BY(mLock) = 0;
187 int32_t mA2dpConnectionJavaServiceCancels GUARDED_BY(mLock) = 0;
188 int32_t mA2dpConnectionUnknowns GUARDED_BY(mLock) = 0;
Andy Hungce9b6632020-04-28 20:15:17 -0700189 } mDeviceConnection{*this};
Joey Poomarin52989982020-03-05 17:40:49 +0800190
jiabin515eb092020-11-18 17:55:52 -0800191 // AAudioStreamInfo is a nested class which collect aaudio stream info from both client and
192 // server side.
193 class AAudioStreamInfo {
194 public:
195 // All the enum here must be kept the same as the ones defined in atoms.proto
196 enum CallerPath {
197 CALLER_PATH_UNKNOWN = 0,
198 CALLER_PATH_LEGACY = 1,
199 CALLER_PATH_MMAP = 2,
200 };
201
202 explicit AAudioStreamInfo(AudioAnalytics &audioAnalytics)
203 : mAudioAnalytics(audioAnalytics) {}
204
205 void endAAudioStream(
206 const std::shared_ptr<const android::mediametrics::Item> &item,
207 CallerPath path) const;
208
209 private:
210
211 AudioAnalytics &mAudioAnalytics;
212 } mAAudioStreamInfo{*this};
213
Andy Hung5be90c82021-03-30 14:30:20 -0700214 AudioPowerUsage mAudioPowerUsage;
Andy Hung06f3aba2019-12-03 16:36:42 -0800215};
216
217} // namespace android::mediametrics