blob: 1c71f5ce19085d95ea7c0832fe703be0226f1d4c [file] [log] [blame]
Ray Essick3938dc62016-11-01 08:56:56 -07001/*
2 * Copyright (C) 2016 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
Ray Essickf27e9872019-12-07 06:28:46 -080017#define LOG_TAG "mediametrics::Item"
Ray Essick3938dc62016-11-01 08:56:56 -070018
Ray Essick3938dc62016-11-01 08:56:56 -070019#include <inttypes.h>
Ray Essickb5fac8e2016-12-12 11:33:56 -080020#include <stdlib.h>
21#include <string.h>
22#include <sys/types.h>
Ray Essick3938dc62016-11-01 08:56:56 -070023
Andy Hunga87e69c2019-10-18 10:07:40 -070024#include <mutex>
Andy Hung3253f2d2019-10-21 14:50:07 -070025#include <set>
Andy Hung5088e1a2021-11-11 09:17:21 -080026#include <unordered_map>
Andy Hunga87e69c2019-10-18 10:07:40 -070027
Ray Essick3938dc62016-11-01 08:56:56 -070028#include <binder/Parcel.h>
Andy Hung7d391082020-04-18 15:03:51 -070029#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <utils/Errors.h>
31#include <utils/Log.h>
Ray Essick3938dc62016-11-01 08:56:56 -070032#include <utils/SortedVector.h>
33#include <utils/threads.h>
34
Andy Hung49ca44e2020-11-10 22:14:58 -080035#include <android/media/BnMediaMetricsService.h> // for direct Binder access
36#include <android/media/IMediaMetricsService.h>
Ray Essick3938dc62016-11-01 08:56:56 -070037#include <binder/IServiceManager.h>
Ray Essickf27e9872019-12-07 06:28:46 -080038#include <media/MediaMetricsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070039#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070040
Andy Hung1efc9c62019-12-03 13:43:33 -080041// Max per-property string size before truncation in toString().
42// Do not make too large, as this is used for dumpsys purposes.
43static constexpr size_t kMaxPropertyStringSize = 4096;
44
Ray Essickf27e9872019-12-07 06:28:46 -080045namespace android::mediametrics {
Ray Essick3938dc62016-11-01 08:56:56 -070046
47#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080048#define DEBUG_API 0
49#define DEBUG_ALLOCATIONS 0
50
51// after this many failed attempts, we stop trying [from this process] and just say that
52// the service is off.
53#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070054
Andy Hung5088e1a2021-11-11 09:17:21 -080055static const std::unordered_map<std::string, int32_t>& getErrorStringMap() {
56 // DO NOT MODIFY VALUES (OK to add new ones).
57 // This may be found in frameworks/av/media/libmediametrics/include/MediaMetricsConstants.h
58 static std::unordered_map<std::string, int32_t> map{
59 {"", NO_ERROR},
60 {AMEDIAMETRICS_PROP_ERROR_VALUE_ARGUMENT, BAD_VALUE},
61 {AMEDIAMETRICS_PROP_ERROR_VALUE_IO, DEAD_OBJECT},
62 {AMEDIAMETRICS_PROP_ERROR_VALUE_MEMORY, NO_MEMORY},
63 {AMEDIAMETRICS_PROP_ERROR_VALUE_SECURITY, PERMISSION_DENIED},
64 {AMEDIAMETRICS_PROP_ERROR_VALUE_STATE, INVALID_OPERATION},
65 {AMEDIAMETRICS_PROP_ERROR_VALUE_TIMEOUT, WOULD_BLOCK},
66 {AMEDIAMETRICS_PROP_ERROR_VALUE_UNKNOWN, UNKNOWN_ERROR},
67 };
68 return map;
69}
70
71status_t errorStringToStatus(const char *error) {
72 const auto& map = getErrorStringMap();
73 if (error == nullptr || error == "") return NO_ERROR;
74 auto it = map.find(error);
75 if (it != map.end()) {
76 return it->second;
77 }
78 return UNKNOWN_ERROR;
79}
80
Ray Essickf27e9872019-12-07 06:28:46 -080081mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
82 mediametrics::Item *item = (android::mediametrics::Item *) handle;
Ray Essickbf536ac2019-08-26 11:04:28 -070083 return item;
84}
85
Ray Essickf27e9872019-12-07 06:28:46 -080086mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
Ray Essickbf536ac2019-08-26 11:04:28 -070087 mediametrics_handle_t handle = (mediametrics_handle_t) item;
88 return handle;
89}
90
Ray Essickf27e9872019-12-07 06:28:46 -080091mediametrics::Item::~Item() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080092 if (DEBUG_ALLOCATIONS) {
Ray Essickf27e9872019-12-07 06:28:46 -080093 ALOGD("Destroy mediametrics::Item @ %p", this);
Ray Essickb5fac8e2016-12-12 11:33:56 -080094 }
Ray Essickb5fac8e2016-12-12 11:33:56 -080095}
96
Ray Essickf27e9872019-12-07 06:28:46 -080097mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
Ray Essick3938dc62016-11-01 08:56:56 -070098 mTimestamp = ts;
99 return *this;
100}
101
Ray Essickf27e9872019-12-07 06:28:46 -0800102nsecs_t mediametrics::Item::getTimestamp() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700103 return mTimestamp;
104}
105
Ray Essickf27e9872019-12-07 06:28:46 -0800106mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
Ray Essick3938dc62016-11-01 08:56:56 -0700107 mPid = pid;
108 return *this;
109}
110
Ray Essickf27e9872019-12-07 06:28:46 -0800111pid_t mediametrics::Item::getPid() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700112 return mPid;
113}
114
Ray Essickf27e9872019-12-07 06:28:46 -0800115mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
Ray Essick3938dc62016-11-01 08:56:56 -0700116 mUid = uid;
117 return *this;
118}
119
Ray Essickf27e9872019-12-07 06:28:46 -0800120uid_t mediametrics::Item::getUid() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700121 return mUid;
122}
123
Ray Essickf27e9872019-12-07 06:28:46 -0800124mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700125 mPkgName = pkgName;
126 return *this;
127}
128
Ray Essickf27e9872019-12-07 06:28:46 -0800129mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700130 mPkgVersionCode = pkgVersionCode;
131 return *this;
132}
133
Ray Essickf27e9872019-12-07 06:28:46 -0800134int64_t mediametrics::Item::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700135 return mPkgVersionCode;
136}
137
Ray Essick3938dc62016-11-01 08:56:56 -0700138// remove indicated keys and their values
139// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800140size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700141 size_t zapped = 0;
142 for (size_t i = 0; i < n; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800143 zapped += mProps.erase(attrs[i]);
Ray Essick3938dc62016-11-01 08:56:56 -0700144 }
145 return zapped;
146}
147
148// remove any keys NOT in the provided list
149// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800150size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700151 std::set<std::string> check(attrs, attrs + n);
152 size_t zapped = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800153 for (auto it = mProps.begin(); it != mProps.end();) {
154 if (check.find(it->first) != check.end()) {
155 ++it;
Andy Hung3253f2d2019-10-21 14:50:07 -0700156 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800157 it = mProps.erase(it);
158 ++zapped;
Ray Essick3938dc62016-11-01 08:56:56 -0700159 }
160 }
161 return zapped;
162}
163
Ray Essick3938dc62016-11-01 08:56:56 -0700164// Parcel / serialize things for binder calls
165//
166
Ray Essickf27e9872019-12-07 06:28:46 -0800167status_t mediametrics::Item::readFromParcel(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700168 int32_t version;
169 status_t status = data.readInt32(&version);
170 if (status != NO_ERROR) return status;
Ray Essickba8c4842019-01-18 11:35:33 -0800171
Andy Hung3253f2d2019-10-21 14:50:07 -0700172 switch (version) {
173 case 0:
174 return readFromParcel0(data);
175 default:
176 ALOGE("%s: unsupported parcel version: %d", __func__, version);
177 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800178 }
179}
180
Ray Essickf27e9872019-12-07 06:28:46 -0800181status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700182 const char *s = data.readCString();
183 mKey = s == nullptr ? "" : s;
184 int32_t pid, uid;
185 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
186 if (status != NO_ERROR) return status;
187 mPid = (pid_t)pid;
188 mUid = (uid_t)uid;
189 s = data.readCString();
190 mPkgName = s == nullptr ? "" : s;
191 int32_t count;
192 int64_t version, timestamp;
193 status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
194 if (status != NO_ERROR) return status;
195 if (count < 0) return BAD_VALUE;
196 mPkgVersionCode = version;
197 mTimestamp = timestamp;
Andy Hung47e58d62019-12-06 18:40:19 -0800198 for (int i = 0; i < count; i++) {
199 Prop prop;
200 status_t status = prop.readFromParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700201 if (status != NO_ERROR) return status;
Andy Hung47e58d62019-12-06 18:40:19 -0800202 mProps[prop.getName()] = std::move(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700203 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700204 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700205}
206
Ray Essickf27e9872019-12-07 06:28:46 -0800207status_t mediametrics::Item::writeToParcel(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700208 if (data == nullptr) return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800209
Andy Hung3253f2d2019-10-21 14:50:07 -0700210 const int32_t version = 0;
211 status_t status = data->writeInt32(version);
212 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700213
Andy Hung3253f2d2019-10-21 14:50:07 -0700214 switch (version) {
215 case 0:
216 return writeToParcel0(data);
217 default:
218 ALOGE("%s: unsupported parcel version: %d", __func__, version);
219 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800220 }
221}
222
Ray Essickf27e9872019-12-07 06:28:46 -0800223status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700224 status_t status =
225 data->writeCString(mKey.c_str())
226 ?: data->writeInt32(mPid)
227 ?: data->writeInt32(mUid)
228 ?: data->writeCString(mPkgName.c_str())
229 ?: data->writeInt64(mPkgVersionCode)
230 ?: data->writeInt64(mTimestamp);
231 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700232
Andy Hung47e58d62019-12-06 18:40:19 -0800233 data->writeInt32((int32_t)mProps.size());
234 for (auto &prop : *this) {
235 status = prop.writeToParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700236 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700237 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700238 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700239}
240
Ray Essickf27e9872019-12-07 06:28:46 -0800241const char *mediametrics::Item::toCString() {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800242 std::string val = toString();
Ray Essick20147322018-11-17 09:08:39 -0800243 return strdup(val.c_str());
244}
245
Andy Hung3b4c1f02020-01-23 18:58:32 -0800246/*
247 * Similar to audio_utils/clock.h but customized for displaying mediametrics time.
248 */
249
250void nsToString(int64_t ns, char *buffer, size_t bufferSize, PrintFormat format)
251{
252 if (bufferSize == 0) return;
253
254 const int one_second = 1000000000;
255 const time_t sec = ns / one_second;
256 struct tm tm;
257
258 // Supported on bionic, glibc, and macOS, but not mingw.
259 if (localtime_r(&sec, &tm) == NULL) {
260 buffer[0] = '\0';
261 return;
262 }
263
264 switch (format) {
265 default:
266 case kPrintFormatLong:
267 if (snprintf(buffer, bufferSize, "%02d-%02d %02d:%02d:%02d.%03d",
268 tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
269 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
270 (int)(ns % one_second / 1000000)) < 0) {
271 buffer[0] = '\0'; // null terminate on format error, which should not happen
272 }
273 break;
274 case kPrintFormatShort:
275 if (snprintf(buffer, bufferSize, "%02d:%02d:%02d.%03d",
276 tm.tm_hour, tm.tm_min, tm.tm_sec,
277 (int)(ns % one_second / 1000000)) < 0) {
278 buffer[0] = '\0'; // null terminate on format error, which should not happen
279 }
280 break;
281 }
Ray Essickf65f4212017-08-31 11:41:19 -0700282}
Ray Essick3938dc62016-11-01 08:56:56 -0700283
Andy Hung3b4c1f02020-01-23 18:58:32 -0800284std::string mediametrics::Item::toString() const {
Ray Essick783bd0d2018-01-11 11:10:35 -0800285 std::string result;
Andy Hung1efc9c62019-12-03 13:43:33 -0800286 char buffer[kMaxPropertyStringSize];
Ray Essick3938dc62016-11-01 08:56:56 -0700287
Andy Hung3b4c1f02020-01-23 18:58:32 -0800288 snprintf(buffer, sizeof(buffer), "{%s, (%s), (%s, %d, %d)",
289 mKey.c_str(),
290 timeStringFromNs(mTimestamp, kPrintFormatLong).time,
291 mPkgName.c_str(), mPid, mUid
292 );
Ray Essickf65f4212017-08-31 11:41:19 -0700293 result.append(buffer);
Andy Hung3b4c1f02020-01-23 18:58:32 -0800294 bool first = true;
Andy Hung47e58d62019-12-06 18:40:19 -0800295 for (auto &prop : *this) {
Andy Hungb7aadb32019-12-09 19:40:42 -0800296 prop.toStringBuffer(buffer, sizeof(buffer));
Andy Hung3b4c1f02020-01-23 18:58:32 -0800297 result += first ? ", (" : ", ";
298 result += buffer;
299 first = false;
Ray Essick3938dc62016-11-01 08:56:56 -0700300 }
Andy Hung3b4c1f02020-01-23 18:58:32 -0800301 result.append(")}");
Ray Essick3938dc62016-11-01 08:56:56 -0700302 return result;
303}
304
305// for the lazy, we offer methods that finds the service and
306// calls the appropriate daemon
Ray Essickf27e9872019-12-07 06:28:46 -0800307bool mediametrics::Item::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700308 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Andy Hung49ca44e2020-11-10 22:14:58 -0800309
310 char *str;
311 size_t size;
312 status_t status = writeToByteString(&str, &size);
313 if (status == NO_ERROR) {
314 status = submitBuffer(str, size);
George Burgess IV14dadb12021-02-03 14:04:09 -0800315 free(str);
Andy Hung49ca44e2020-11-10 22:14:58 -0800316 }
317 if (status != NO_ERROR) {
318 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700319 return false;
320 }
Andy Hung49ca44e2020-11-10 22:14:58 -0800321 return true;
Ray Essick3938dc62016-11-01 08:56:56 -0700322}
323
Ray Essick3938dc62016-11-01 08:56:56 -0700324//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800325bool BaseItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700326 // completely skip logging from certain UIDs. We do this here
327 // to avoid the multi-second timeouts while we learn that
328 // sepolicy will not let us find the service.
329 // We do this only for a select set of UIDs
330 // The sepolicy protection is still in place, we just want a faster
331 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700332
Andy Hunga87e69c2019-10-18 10:07:40 -0700333 // This is checked only once in the lifetime of the process.
334 const uid_t uid = getuid();
335 switch (uid) {
336 case AID_RADIO: // telephony subsystem, RIL
337 return false;
Ahaan Ugaleb5aee612021-05-26 14:50:13 -0700338 default:
339 // Some isolated processes can access the audio system; see
340 // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead
341 // of also allowing access to the MediaMetrics service, it's simpler to just disable it for
342 // now.
343 // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or
344 // make this disabling specific to that process.
345 if (uid >= AID_ISOLATED_START && uid <= AID_ISOLATED_END) {
346 return false;
347 }
348 break;
Andy Hunga87e69c2019-10-18 10:07:40 -0700349 }
350
Ray Essickf27e9872019-12-07 06:28:46 -0800351 int enabled = property_get_int32(Item::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700352 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800353 enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700354 }
355 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800356 enabled = Item::EnabledProperty_default;
Ray Essick3938dc62016-11-01 08:56:56 -0700357 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700358 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700359}
360
Ray Essick2ab3c432017-10-02 09:29:49 -0700361// monitor health of our connection to the metrics service
362class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
363 virtual void binderDied(const wp<IBinder> &) {
364 ALOGW("Reacquire service connection on next request");
Andy Hung1efc9c62019-12-03 13:43:33 -0800365 BaseItem::dropInstance();
Ray Essick2ab3c432017-10-02 09:29:49 -0700366 }
367};
368
Andy Hunga87e69c2019-10-18 10:07:40 -0700369static sp<MediaMetricsDeathNotifier> sNotifier;
370// static
Andy Hung49ca44e2020-11-10 22:14:58 -0800371sp<media::IMediaMetricsService> BaseItem::sMediaMetricsService;
Andy Hunga87e69c2019-10-18 10:07:40 -0700372static std::mutex sServiceMutex;
373static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700374
375// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800376void BaseItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700377 std::lock_guard _l(sServiceMutex);
378 sRemainingBindAttempts = SVC_TRIES;
Ray Essickf27e9872019-12-07 06:28:46 -0800379 sMediaMetricsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700380}
381
Andy Hung1efc9c62019-12-03 13:43:33 -0800382// static
Andy Hung49ca44e2020-11-10 22:14:58 -0800383status_t BaseItem::submitBuffer(const char *buffer, size_t size) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800384 ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
Andy Hung49ca44e2020-11-10 22:14:58 -0800385
386 // Validate size
387 if (size > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
388
389 // Do we have the service available?
390 sp<media::IMediaMetricsService> svc = getService();
391 if (svc == nullptr) return NO_INIT;
392
393 ::android::status_t status = NO_ERROR;
394 if constexpr (/* DISABLES CODE */ (false)) {
395 // THIS PATH IS FOR REFERENCE ONLY.
396 // It is compiled so that any changes to IMediaMetricsService::submitBuffer()
397 // will lead here. If this code is changed, the else branch must
398 // be changed as well.
399 //
400 // Use the AIDL calling interface - this is a bit slower as a byte vector must be
401 // constructed. As the call is one-way, the only a transaction error occurs.
402 status = svc->submitBuffer({buffer, buffer + size}).transactionError();
403 } else {
404 // Use the Binder calling interface - this direct implementation avoids
405 // malloc/copy/free for the vector and reduces the overhead for logging.
406 // We based this off of the AIDL generated file:
407 // out/soong/.intermediates/frameworks/av/media/libmediametrics/mediametricsservice-aidl-unstable-cpp-source/gen/android/media/IMediaMetricsService.cpp
408 // TODO: Create an AIDL C++ back end optimized form of vector writing.
409 ::android::Parcel _aidl_data;
410 ::android::Parcel _aidl_reply; // we don't care about this as it is one-way.
411
412 status = _aidl_data.writeInterfaceToken(svc->getInterfaceDescriptor());
413 if (status != ::android::OK) goto _aidl_error;
414
415 status = _aidl_data.writeInt32(static_cast<int32_t>(size));
416 if (status != ::android::OK) goto _aidl_error;
417
418 status = _aidl_data.write(buffer, static_cast<int32_t>(size));
419 if (status != ::android::OK) goto _aidl_error;
420
421 status = ::android::IInterface::asBinder(svc)->transact(
422 ::android::media::BnMediaMetricsService::TRANSACTION_submitBuffer,
423 _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
424
425 // AIDL permits setting a default implementation for additional functionality.
426 // See go/aog/713984. This is not used here.
427 // if (status == ::android::UNKNOWN_TRANSACTION
428 // && ::android::media::IMediaMetricsService::getDefaultImpl()) {
429 // status = ::android::media::IMediaMetricsService::getDefaultImpl()
430 // ->submitBuffer(immutableByteVectorFromBuffer(buffer, size))
431 // .transactionError();
432 // }
Andy Hung1efc9c62019-12-03 13:43:33 -0800433 }
Andy Hung49ca44e2020-11-10 22:14:58 -0800434
435 if (status == NO_ERROR) return NO_ERROR;
436
437 _aidl_error:
438 ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
439 return status;
Andy Hung1efc9c62019-12-03 13:43:33 -0800440}
441
Ray Essick3938dc62016-11-01 08:56:56 -0700442//static
Andy Hung49ca44e2020-11-10 22:14:58 -0800443sp<media::IMediaMetricsService> BaseItem::getService() {
Ray Essickd38e1742017-01-23 15:17:06 -0800444 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700445 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700446
447 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700448 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
449 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700450 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700451 std::lock_guard _l(sServiceMutex);
452 // think of remainingBindAttempts as telling us whether service == nullptr because
453 // (1) we haven't tried to initialize it yet
454 // (2) we've tried to initialize it, but failed.
Ray Essickf27e9872019-12-07 06:28:46 -0800455 if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700456 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700457 sp<IServiceManager> sm = defaultServiceManager();
458 if (sm != nullptr) {
459 sp<IBinder> binder = sm->getService(String16(servicename));
460 if (binder != nullptr) {
Andy Hung49ca44e2020-11-10 22:14:58 -0800461 sMediaMetricsService = interface_cast<media::IMediaMetricsService>(binder);
Andy Hunga87e69c2019-10-18 10:07:40 -0700462 sNotifier = new MediaMetricsDeathNotifier();
463 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700464 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700465 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700466 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700467 } else {
468 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700469 }
Ray Essickf27e9872019-12-07 06:28:46 -0800470 if (sMediaMetricsService == nullptr) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700471 if (sRemainingBindAttempts > 0) {
472 sRemainingBindAttempts--;
473 }
474 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
475 __func__, servicename, badness);
476 }
Ray Essick3938dc62016-11-01 08:56:56 -0700477 }
Ray Essickf27e9872019-12-07 06:28:46 -0800478 return sMediaMetricsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700479}
480
Andy Hung1efc9c62019-12-03 13:43:33 -0800481
Ray Essickf27e9872019-12-07 06:28:46 -0800482status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700483{
484 if (pbuffer == nullptr || plength == nullptr)
485 return BAD_VALUE;
486
487 // get size
488 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
489 if (keySizeZeroTerminated > UINT16_MAX) {
490 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
491 return INVALID_OPERATION;
492 }
493 const uint16_t version = 0;
Andy Hung1efc9c62019-12-03 13:43:33 -0800494 const uint32_t header_size =
495 sizeof(uint32_t) // total size
496 + sizeof(header_size) // header size
497 + sizeof(version) // encoding version
498 + sizeof(uint16_t) // key size
Andy Hung3253f2d2019-10-21 14:50:07 -0700499 + keySizeZeroTerminated // key, zero terminated
Andy Hung1efc9c62019-12-03 13:43:33 -0800500 + sizeof(int32_t) // pid
501 + sizeof(int32_t) // uid
502 + sizeof(int64_t) // timestamp
Andy Hung3253f2d2019-10-21 14:50:07 -0700503 ;
504
Andy Hung1efc9c62019-12-03 13:43:33 -0800505 uint32_t size = header_size
Andy Hung3253f2d2019-10-21 14:50:07 -0700506 + sizeof(uint32_t) // # properties
507 ;
Andy Hung47e58d62019-12-06 18:40:19 -0800508 for (auto &prop : *this) {
509 const size_t propSize = prop.getByteStringSize();
Andy Hung1efc9c62019-12-03 13:43:33 -0800510 if (propSize > UINT16_MAX) {
Andy Hung47e58d62019-12-06 18:40:19 -0800511 ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize);
Andy Hung3253f2d2019-10-21 14:50:07 -0700512 return INVALID_OPERATION;
513 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800514 if (__builtin_add_overflow(size, propSize, &size)) {
Andy Hung47e58d62019-12-06 18:40:19 -0800515 ALOGW("%s: item size overflow at property %s", __func__, prop.getName());
Andy Hung1efc9c62019-12-03 13:43:33 -0800516 return INVALID_OPERATION;
517 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700518 }
519
Andy Hung1efc9c62019-12-03 13:43:33 -0800520 // since we fill every byte in the buffer (there is no padding),
521 // malloc is used here instead of calloc.
522 char * const build = (char *)malloc(size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700523 if (build == nullptr) return NO_MEMORY;
524
525 char *filling = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800526 char *buildmax = build + size;
527 if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
528 || insert(header_size, &filling, buildmax) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700529 || insert(version, &filling, buildmax) != NO_ERROR
530 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
531 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
532 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
533 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
534 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
Andy Hung47e58d62019-12-06 18:40:19 -0800535 || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800536 ALOGE("%s:could not write header", __func__); // shouldn't happen
Andy Hung3253f2d2019-10-21 14:50:07 -0700537 free(build);
538 return INVALID_OPERATION;
539 }
Andy Hung47e58d62019-12-06 18:40:19 -0800540 for (auto &prop : *this) {
541 if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700542 free(build);
Andy Hung1efc9c62019-12-03 13:43:33 -0800543 // shouldn't happen
Andy Hung47e58d62019-12-06 18:40:19 -0800544 ALOGE("%s:could not write prop %s", __func__, prop.getName());
Andy Hung3253f2d2019-10-21 14:50:07 -0700545 return INVALID_OPERATION;
546 }
547 }
548
549 if (filling != buildmax) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800550 ALOGE("%s: problems populating; wrote=%d planned=%d",
551 __func__, (int)(filling - build), (int)size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700552 free(build);
553 return INVALID_OPERATION;
554 }
555 *pbuffer = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800556 *plength = size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700557 return NO_ERROR;
558}
559
Ray Essickf27e9872019-12-07 06:28:46 -0800560status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
Andy Hung3253f2d2019-10-21 14:50:07 -0700561{
562 if (bufferptr == nullptr) return BAD_VALUE;
563
564 const char *read = bufferptr;
565 const char *readend = bufferptr + length;
566
Andy Hung1efc9c62019-12-03 13:43:33 -0800567 uint32_t size;
568 uint32_t header_size;
569 uint16_t version;
570 uint16_t key_size;
Andy Hungb7aadb32019-12-09 19:40:42 -0800571 std::string key;
Andy Hung3253f2d2019-10-21 14:50:07 -0700572 int32_t pid;
573 int32_t uid;
574 int64_t timestamp;
575 uint32_t propCount;
Andy Hung1efc9c62019-12-03 13:43:33 -0800576 if (extract(&size, &read, readend) != NO_ERROR
577 || extract(&header_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700578 || extract(&version, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800579 || extract(&key_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700580 || extract(&key, &read, readend) != NO_ERROR
581 || extract(&pid, &read, readend) != NO_ERROR
582 || extract(&uid, &read, readend) != NO_ERROR
583 || extract(&timestamp, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800584 || size > length
Andy Hungb7aadb32019-12-09 19:40:42 -0800585 || key.size() + 1 != key_size
Andy Hung1efc9c62019-12-03 13:43:33 -0800586 || header_size > size) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800587 ALOGW("%s: invalid header", __func__);
Andy Hung3253f2d2019-10-21 14:50:07 -0700588 return INVALID_OPERATION;
589 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800590 mKey = std::move(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700591 const size_t pos = read - bufferptr;
Andy Hung1efc9c62019-12-03 13:43:33 -0800592 if (pos > header_size) {
593 ALOGW("%s: invalid header pos:%zu > header_size:%u",
594 __func__, pos, header_size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700595 return INVALID_OPERATION;
Andy Hung1efc9c62019-12-03 13:43:33 -0800596 } else if (pos < header_size) {
597 ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
598 __func__, pos, header_size);
599 read += (header_size - pos);
Andy Hung3253f2d2019-10-21 14:50:07 -0700600 }
601 if (extract(&propCount, &read, readend) != NO_ERROR) {
602 ALOGD("%s: cannot read prop count", __func__);
603 return INVALID_OPERATION;
604 }
605 mPid = pid;
606 mUid = uid;
607 mTimestamp = timestamp;
608 for (size_t i = 0; i < propCount; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800609 Prop prop;
610 if (prop.readFromByteString(&read, readend) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800611 ALOGW("%s: cannot read prop %zu", __func__, i);
Andy Hung3253f2d2019-10-21 14:50:07 -0700612 return INVALID_OPERATION;
613 }
Andy Hung47e58d62019-12-06 18:40:19 -0800614 mProps[prop.getName()] = std::move(prop);
Andy Hung3253f2d2019-10-21 14:50:07 -0700615 }
616 return NO_ERROR;
617}
618
Ray Essickf27e9872019-12-07 06:28:46 -0800619status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
Andy Hung3253f2d2019-10-21 14:50:07 -0700620{
621 const char *key = data.readCString();
622 if (key == nullptr) return BAD_VALUE;
623 int32_t type;
624 status_t status = data.readInt32(&type);
625 if (status != NO_ERROR) return status;
626 switch (type) {
Andy Hungb7aadb32019-12-09 19:40:42 -0800627 case mediametrics::kTypeInt32: {
628 int32_t value;
629 status = data.readInt32(&value);
630 if (status != NO_ERROR) return status;
631 mElem = value;
632 } break;
633 case mediametrics::kTypeInt64: {
634 int64_t value;
635 status = data.readInt64(&value);
636 if (status != NO_ERROR) return status;
637 mElem = value;
638 } break;
639 case mediametrics::kTypeDouble: {
640 double value;
641 status = data.readDouble(&value);
642 if (status != NO_ERROR) return status;
643 mElem = value;
644 } break;
Andy Hung47e58d62019-12-06 18:40:19 -0800645 case mediametrics::kTypeCString: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700646 const char *s = data.readCString();
647 if (s == nullptr) return BAD_VALUE;
Andy Hungb7aadb32019-12-09 19:40:42 -0800648 mElem = s;
649 } break;
Andy Hung47e58d62019-12-06 18:40:19 -0800650 case mediametrics::kTypeRate: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700651 std::pair<int64_t, int64_t> rate;
652 status = data.readInt64(&rate.first)
653 ?: data.readInt64(&rate.second);
Andy Hungb7aadb32019-12-09 19:40:42 -0800654 if (status != NO_ERROR) return status;
655 mElem = rate;
656 } break;
657 case mediametrics::kTypeNone: {
658 mElem = std::monostate{};
659 } break;
Andy Hung3253f2d2019-10-21 14:50:07 -0700660 default:
Andy Hungb7aadb32019-12-09 19:40:42 -0800661 ALOGE("%s: reading bad item type: %d", __func__, type);
Andy Hung3253f2d2019-10-21 14:50:07 -0700662 return BAD_VALUE;
663 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800664 setName(key);
665 return NO_ERROR;
Andy Hung3253f2d2019-10-21 14:50:07 -0700666}
667
Ray Essickf27e9872019-12-07 06:28:46 -0800668status_t mediametrics::Item::Prop::readFromByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700669 const char **bufferpptr, const char *bufferptrmax)
670{
671 uint16_t len;
Andy Hungb7aadb32019-12-09 19:40:42 -0800672 std::string name;
Andy Hung3253f2d2019-10-21 14:50:07 -0700673 uint8_t type;
674 status_t status = extract(&len, bufferpptr, bufferptrmax)
675 ?: extract(&type, bufferpptr, bufferptrmax)
676 ?: extract(&name, bufferpptr, bufferptrmax);
677 if (status != NO_ERROR) return status;
Andy Hungb7aadb32019-12-09 19:40:42 -0800678 switch (type) {
679 case mediametrics::kTypeInt32: {
680 int32_t value;
681 status = extract(&value, bufferpptr, bufferptrmax);
682 if (status != NO_ERROR) return status;
683 mElem = value;
684 } break;
685 case mediametrics::kTypeInt64: {
686 int64_t value;
687 status = extract(&value, bufferpptr, bufferptrmax);
688 if (status != NO_ERROR) return status;
689 mElem = value;
690 } break;
691 case mediametrics::kTypeDouble: {
692 double value;
693 status = extract(&value, bufferpptr, bufferptrmax);
694 if (status != NO_ERROR) return status;
695 mElem = value;
696 } break;
697 case mediametrics::kTypeRate: {
698 std::pair<int64_t, int64_t> value;
699 status = extract(&value.first, bufferpptr, bufferptrmax)
700 ?: extract(&value.second, bufferpptr, bufferptrmax);
701 if (status != NO_ERROR) return status;
702 mElem = value;
703 } break;
704 case mediametrics::kTypeCString: {
705 std::string value;
706 status = extract(&value, bufferpptr, bufferptrmax);
707 if (status != NO_ERROR) return status;
708 mElem = std::move(value);
709 } break;
710 case mediametrics::kTypeNone: {
711 mElem = std::monostate{};
712 } break;
Andy Hung3253f2d2019-10-21 14:50:07 -0700713 default:
Andy Hung3253f2d2019-10-21 14:50:07 -0700714 ALOGE("%s: found bad prop type: %d, name %s",
Andy Hungb7aadb32019-12-09 19:40:42 -0800715 __func__, (int)type, mName.c_str()); // no payload sent
Andy Hung3253f2d2019-10-21 14:50:07 -0700716 return BAD_VALUE;
717 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800718 mName = name;
719 return NO_ERROR;
Andy Hung3253f2d2019-10-21 14:50:07 -0700720}
721
Ray Essickf27e9872019-12-07 06:28:46 -0800722} // namespace android::mediametrics