blob: a8350ea14d612b2bbb69d04fdb41e1db9b4ff847 [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 Hunga87e69c2019-10-18 10:07:40 -070026
Ray Essick3938dc62016-11-01 08:56:56 -070027#include <binder/Parcel.h>
Andy Hung7d391082020-04-18 15:03:51 -070028#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070029#include <utils/Errors.h>
30#include <utils/Log.h>
Ray Essick3938dc62016-11-01 08:56:56 -070031#include <utils/SortedVector.h>
32#include <utils/threads.h>
33
Andy Hung49ca44e2020-11-10 22:14:58 -080034#include <android/media/BnMediaMetricsService.h> // for direct Binder access
35#include <android/media/IMediaMetricsService.h>
Ray Essick3938dc62016-11-01 08:56:56 -070036#include <binder/IServiceManager.h>
Ray Essickf27e9872019-12-07 06:28:46 -080037#include <media/MediaMetricsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070038#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070039
Andy Hung1efc9c62019-12-03 13:43:33 -080040// Max per-property string size before truncation in toString().
41// Do not make too large, as this is used for dumpsys purposes.
42static constexpr size_t kMaxPropertyStringSize = 4096;
43
Ray Essickf27e9872019-12-07 06:28:46 -080044namespace android::mediametrics {
Ray Essick3938dc62016-11-01 08:56:56 -070045
46#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080047#define DEBUG_API 0
48#define DEBUG_ALLOCATIONS 0
49
50// after this many failed attempts, we stop trying [from this process] and just say that
51// the service is off.
52#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070053
Ray Essickf27e9872019-12-07 06:28:46 -080054mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
55 mediametrics::Item *item = (android::mediametrics::Item *) handle;
Ray Essickbf536ac2019-08-26 11:04:28 -070056 return item;
57}
58
Ray Essickf27e9872019-12-07 06:28:46 -080059mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
Ray Essickbf536ac2019-08-26 11:04:28 -070060 mediametrics_handle_t handle = (mediametrics_handle_t) item;
61 return handle;
62}
63
Ray Essickf27e9872019-12-07 06:28:46 -080064mediametrics::Item::~Item() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080065 if (DEBUG_ALLOCATIONS) {
Ray Essickf27e9872019-12-07 06:28:46 -080066 ALOGD("Destroy mediametrics::Item @ %p", this);
Ray Essickb5fac8e2016-12-12 11:33:56 -080067 }
Ray Essickb5fac8e2016-12-12 11:33:56 -080068}
69
Ray Essickf27e9872019-12-07 06:28:46 -080070mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
Ray Essick3938dc62016-11-01 08:56:56 -070071 mTimestamp = ts;
72 return *this;
73}
74
Ray Essickf27e9872019-12-07 06:28:46 -080075nsecs_t mediametrics::Item::getTimestamp() const {
Ray Essick3938dc62016-11-01 08:56:56 -070076 return mTimestamp;
77}
78
Ray Essickf27e9872019-12-07 06:28:46 -080079mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
Ray Essick3938dc62016-11-01 08:56:56 -070080 mPid = pid;
81 return *this;
82}
83
Ray Essickf27e9872019-12-07 06:28:46 -080084pid_t mediametrics::Item::getPid() const {
Ray Essick3938dc62016-11-01 08:56:56 -070085 return mPid;
86}
87
Ray Essickf27e9872019-12-07 06:28:46 -080088mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
Ray Essick3938dc62016-11-01 08:56:56 -070089 mUid = uid;
90 return *this;
91}
92
Ray Essickf27e9872019-12-07 06:28:46 -080093uid_t mediametrics::Item::getUid() const {
Ray Essick3938dc62016-11-01 08:56:56 -070094 return mUid;
95}
96
Ray Essickf27e9872019-12-07 06:28:46 -080097mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -070098 mPkgName = pkgName;
99 return *this;
100}
101
Ray Essickf27e9872019-12-07 06:28:46 -0800102mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700103 mPkgVersionCode = pkgVersionCode;
104 return *this;
105}
106
Ray Essickf27e9872019-12-07 06:28:46 -0800107int64_t mediametrics::Item::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700108 return mPkgVersionCode;
109}
110
Ray Essick3938dc62016-11-01 08:56:56 -0700111// remove indicated keys and their values
112// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800113size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700114 size_t zapped = 0;
115 for (size_t i = 0; i < n; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800116 zapped += mProps.erase(attrs[i]);
Ray Essick3938dc62016-11-01 08:56:56 -0700117 }
118 return zapped;
119}
120
121// remove any keys NOT in the provided list
122// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800123size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700124 std::set<std::string> check(attrs, attrs + n);
125 size_t zapped = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800126 for (auto it = mProps.begin(); it != mProps.end();) {
127 if (check.find(it->first) != check.end()) {
128 ++it;
Andy Hung3253f2d2019-10-21 14:50:07 -0700129 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800130 it = mProps.erase(it);
131 ++zapped;
Ray Essick3938dc62016-11-01 08:56:56 -0700132 }
133 }
134 return zapped;
135}
136
Ray Essick3938dc62016-11-01 08:56:56 -0700137// Parcel / serialize things for binder calls
138//
139
Ray Essickf27e9872019-12-07 06:28:46 -0800140status_t mediametrics::Item::readFromParcel(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700141 int32_t version;
142 status_t status = data.readInt32(&version);
143 if (status != NO_ERROR) return status;
Ray Essickba8c4842019-01-18 11:35:33 -0800144
Andy Hung3253f2d2019-10-21 14:50:07 -0700145 switch (version) {
146 case 0:
147 return readFromParcel0(data);
148 default:
149 ALOGE("%s: unsupported parcel version: %d", __func__, version);
150 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800151 }
152}
153
Ray Essickf27e9872019-12-07 06:28:46 -0800154status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700155 const char *s = data.readCString();
156 mKey = s == nullptr ? "" : s;
157 int32_t pid, uid;
158 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
159 if (status != NO_ERROR) return status;
160 mPid = (pid_t)pid;
161 mUid = (uid_t)uid;
162 s = data.readCString();
163 mPkgName = s == nullptr ? "" : s;
164 int32_t count;
165 int64_t version, timestamp;
166 status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
167 if (status != NO_ERROR) return status;
168 if (count < 0) return BAD_VALUE;
169 mPkgVersionCode = version;
170 mTimestamp = timestamp;
Andy Hung47e58d62019-12-06 18:40:19 -0800171 for (int i = 0; i < count; i++) {
172 Prop prop;
173 status_t status = prop.readFromParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700174 if (status != NO_ERROR) return status;
Andy Hung47e58d62019-12-06 18:40:19 -0800175 mProps[prop.getName()] = std::move(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700176 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700177 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700178}
179
Ray Essickf27e9872019-12-07 06:28:46 -0800180status_t mediametrics::Item::writeToParcel(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700181 if (data == nullptr) return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800182
Andy Hung3253f2d2019-10-21 14:50:07 -0700183 const int32_t version = 0;
184 status_t status = data->writeInt32(version);
185 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700186
Andy Hung3253f2d2019-10-21 14:50:07 -0700187 switch (version) {
188 case 0:
189 return writeToParcel0(data);
190 default:
191 ALOGE("%s: unsupported parcel version: %d", __func__, version);
192 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800193 }
194}
195
Ray Essickf27e9872019-12-07 06:28:46 -0800196status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700197 status_t status =
198 data->writeCString(mKey.c_str())
199 ?: data->writeInt32(mPid)
200 ?: data->writeInt32(mUid)
201 ?: data->writeCString(mPkgName.c_str())
202 ?: data->writeInt64(mPkgVersionCode)
203 ?: data->writeInt64(mTimestamp);
204 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700205
Andy Hung47e58d62019-12-06 18:40:19 -0800206 data->writeInt32((int32_t)mProps.size());
207 for (auto &prop : *this) {
208 status = prop.writeToParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700209 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700210 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700211 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700212}
213
Ray Essickf27e9872019-12-07 06:28:46 -0800214const char *mediametrics::Item::toCString() {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800215 std::string val = toString();
Ray Essick20147322018-11-17 09:08:39 -0800216 return strdup(val.c_str());
217}
218
Andy Hung3b4c1f02020-01-23 18:58:32 -0800219/*
220 * Similar to audio_utils/clock.h but customized for displaying mediametrics time.
221 */
222
223void nsToString(int64_t ns, char *buffer, size_t bufferSize, PrintFormat format)
224{
225 if (bufferSize == 0) return;
226
227 const int one_second = 1000000000;
228 const time_t sec = ns / one_second;
229 struct tm tm;
230
231 // Supported on bionic, glibc, and macOS, but not mingw.
232 if (localtime_r(&sec, &tm) == NULL) {
233 buffer[0] = '\0';
234 return;
235 }
236
237 switch (format) {
238 default:
239 case kPrintFormatLong:
240 if (snprintf(buffer, bufferSize, "%02d-%02d %02d:%02d:%02d.%03d",
241 tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
242 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
243 (int)(ns % one_second / 1000000)) < 0) {
244 buffer[0] = '\0'; // null terminate on format error, which should not happen
245 }
246 break;
247 case kPrintFormatShort:
248 if (snprintf(buffer, bufferSize, "%02d:%02d:%02d.%03d",
249 tm.tm_hour, tm.tm_min, tm.tm_sec,
250 (int)(ns % one_second / 1000000)) < 0) {
251 buffer[0] = '\0'; // null terminate on format error, which should not happen
252 }
253 break;
254 }
Ray Essickf65f4212017-08-31 11:41:19 -0700255}
Ray Essick3938dc62016-11-01 08:56:56 -0700256
Andy Hung3b4c1f02020-01-23 18:58:32 -0800257std::string mediametrics::Item::toString() const {
Ray Essick783bd0d2018-01-11 11:10:35 -0800258 std::string result;
Andy Hung1efc9c62019-12-03 13:43:33 -0800259 char buffer[kMaxPropertyStringSize];
Ray Essick3938dc62016-11-01 08:56:56 -0700260
Andy Hung3b4c1f02020-01-23 18:58:32 -0800261 snprintf(buffer, sizeof(buffer), "{%s, (%s), (%s, %d, %d)",
262 mKey.c_str(),
263 timeStringFromNs(mTimestamp, kPrintFormatLong).time,
264 mPkgName.c_str(), mPid, mUid
265 );
Ray Essickf65f4212017-08-31 11:41:19 -0700266 result.append(buffer);
Andy Hung3b4c1f02020-01-23 18:58:32 -0800267 bool first = true;
Andy Hung47e58d62019-12-06 18:40:19 -0800268 for (auto &prop : *this) {
Andy Hungb7aadb32019-12-09 19:40:42 -0800269 prop.toStringBuffer(buffer, sizeof(buffer));
Andy Hung3b4c1f02020-01-23 18:58:32 -0800270 result += first ? ", (" : ", ";
271 result += buffer;
272 first = false;
Ray Essick3938dc62016-11-01 08:56:56 -0700273 }
Andy Hung3b4c1f02020-01-23 18:58:32 -0800274 result.append(")}");
Ray Essick3938dc62016-11-01 08:56:56 -0700275 return result;
276}
277
278// for the lazy, we offer methods that finds the service and
279// calls the appropriate daemon
Ray Essickf27e9872019-12-07 06:28:46 -0800280bool mediametrics::Item::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700281 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Andy Hung49ca44e2020-11-10 22:14:58 -0800282
283 char *str;
284 size_t size;
285 status_t status = writeToByteString(&str, &size);
286 if (status == NO_ERROR) {
287 status = submitBuffer(str, size);
George Burgess IV14dadb12021-02-03 14:04:09 -0800288 free(str);
Andy Hung49ca44e2020-11-10 22:14:58 -0800289 }
290 if (status != NO_ERROR) {
291 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700292 return false;
293 }
Andy Hung49ca44e2020-11-10 22:14:58 -0800294 return true;
Ray Essick3938dc62016-11-01 08:56:56 -0700295}
296
Ray Essick3938dc62016-11-01 08:56:56 -0700297//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800298bool BaseItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700299 // completely skip logging from certain UIDs. We do this here
300 // to avoid the multi-second timeouts while we learn that
301 // sepolicy will not let us find the service.
302 // We do this only for a select set of UIDs
303 // The sepolicy protection is still in place, we just want a faster
304 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700305
Andy Hunga87e69c2019-10-18 10:07:40 -0700306 // This is checked only once in the lifetime of the process.
307 const uid_t uid = getuid();
308 switch (uid) {
309 case AID_RADIO: // telephony subsystem, RIL
310 return false;
311 }
312
Ray Essickf27e9872019-12-07 06:28:46 -0800313 int enabled = property_get_int32(Item::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700314 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800315 enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700316 }
317 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800318 enabled = Item::EnabledProperty_default;
Ray Essick3938dc62016-11-01 08:56:56 -0700319 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700320 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700321}
322
Ray Essick2ab3c432017-10-02 09:29:49 -0700323// monitor health of our connection to the metrics service
324class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
325 virtual void binderDied(const wp<IBinder> &) {
326 ALOGW("Reacquire service connection on next request");
Andy Hung1efc9c62019-12-03 13:43:33 -0800327 BaseItem::dropInstance();
Ray Essick2ab3c432017-10-02 09:29:49 -0700328 }
329};
330
Andy Hunga87e69c2019-10-18 10:07:40 -0700331static sp<MediaMetricsDeathNotifier> sNotifier;
332// static
Andy Hung49ca44e2020-11-10 22:14:58 -0800333sp<media::IMediaMetricsService> BaseItem::sMediaMetricsService;
Andy Hunga87e69c2019-10-18 10:07:40 -0700334static std::mutex sServiceMutex;
335static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700336
337// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800338void BaseItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700339 std::lock_guard _l(sServiceMutex);
340 sRemainingBindAttempts = SVC_TRIES;
Ray Essickf27e9872019-12-07 06:28:46 -0800341 sMediaMetricsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700342}
343
Andy Hung1efc9c62019-12-03 13:43:33 -0800344// static
Andy Hung49ca44e2020-11-10 22:14:58 -0800345status_t BaseItem::submitBuffer(const char *buffer, size_t size) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800346 ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
Andy Hung49ca44e2020-11-10 22:14:58 -0800347
348 // Validate size
349 if (size > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
350
351 // Do we have the service available?
352 sp<media::IMediaMetricsService> svc = getService();
353 if (svc == nullptr) return NO_INIT;
354
355 ::android::status_t status = NO_ERROR;
356 if constexpr (/* DISABLES CODE */ (false)) {
357 // THIS PATH IS FOR REFERENCE ONLY.
358 // It is compiled so that any changes to IMediaMetricsService::submitBuffer()
359 // will lead here. If this code is changed, the else branch must
360 // be changed as well.
361 //
362 // Use the AIDL calling interface - this is a bit slower as a byte vector must be
363 // constructed. As the call is one-way, the only a transaction error occurs.
364 status = svc->submitBuffer({buffer, buffer + size}).transactionError();
365 } else {
366 // Use the Binder calling interface - this direct implementation avoids
367 // malloc/copy/free for the vector and reduces the overhead for logging.
368 // We based this off of the AIDL generated file:
369 // out/soong/.intermediates/frameworks/av/media/libmediametrics/mediametricsservice-aidl-unstable-cpp-source/gen/android/media/IMediaMetricsService.cpp
370 // TODO: Create an AIDL C++ back end optimized form of vector writing.
371 ::android::Parcel _aidl_data;
372 ::android::Parcel _aidl_reply; // we don't care about this as it is one-way.
373
374 status = _aidl_data.writeInterfaceToken(svc->getInterfaceDescriptor());
375 if (status != ::android::OK) goto _aidl_error;
376
377 status = _aidl_data.writeInt32(static_cast<int32_t>(size));
378 if (status != ::android::OK) goto _aidl_error;
379
380 status = _aidl_data.write(buffer, static_cast<int32_t>(size));
381 if (status != ::android::OK) goto _aidl_error;
382
383 status = ::android::IInterface::asBinder(svc)->transact(
384 ::android::media::BnMediaMetricsService::TRANSACTION_submitBuffer,
385 _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
386
387 // AIDL permits setting a default implementation for additional functionality.
388 // See go/aog/713984. This is not used here.
389 // if (status == ::android::UNKNOWN_TRANSACTION
390 // && ::android::media::IMediaMetricsService::getDefaultImpl()) {
391 // status = ::android::media::IMediaMetricsService::getDefaultImpl()
392 // ->submitBuffer(immutableByteVectorFromBuffer(buffer, size))
393 // .transactionError();
394 // }
Andy Hung1efc9c62019-12-03 13:43:33 -0800395 }
Andy Hung49ca44e2020-11-10 22:14:58 -0800396
397 if (status == NO_ERROR) return NO_ERROR;
398
399 _aidl_error:
400 ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
401 return status;
Andy Hung1efc9c62019-12-03 13:43:33 -0800402}
403
Ray Essick3938dc62016-11-01 08:56:56 -0700404//static
Andy Hung49ca44e2020-11-10 22:14:58 -0800405sp<media::IMediaMetricsService> BaseItem::getService() {
Ray Essickd38e1742017-01-23 15:17:06 -0800406 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700407 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700408
409 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700410 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
411 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700412 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700413 std::lock_guard _l(sServiceMutex);
414 // think of remainingBindAttempts as telling us whether service == nullptr because
415 // (1) we haven't tried to initialize it yet
416 // (2) we've tried to initialize it, but failed.
Ray Essickf27e9872019-12-07 06:28:46 -0800417 if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700418 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700419 sp<IServiceManager> sm = defaultServiceManager();
420 if (sm != nullptr) {
421 sp<IBinder> binder = sm->getService(String16(servicename));
422 if (binder != nullptr) {
Andy Hung49ca44e2020-11-10 22:14:58 -0800423 sMediaMetricsService = interface_cast<media::IMediaMetricsService>(binder);
Andy Hunga87e69c2019-10-18 10:07:40 -0700424 sNotifier = new MediaMetricsDeathNotifier();
425 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700426 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700427 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700428 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700429 } else {
430 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700431 }
Ray Essickf27e9872019-12-07 06:28:46 -0800432 if (sMediaMetricsService == nullptr) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700433 if (sRemainingBindAttempts > 0) {
434 sRemainingBindAttempts--;
435 }
436 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
437 __func__, servicename, badness);
438 }
Ray Essick3938dc62016-11-01 08:56:56 -0700439 }
Ray Essickf27e9872019-12-07 06:28:46 -0800440 return sMediaMetricsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700441}
442
Andy Hung1efc9c62019-12-03 13:43:33 -0800443
Ray Essickf27e9872019-12-07 06:28:46 -0800444status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700445{
446 if (pbuffer == nullptr || plength == nullptr)
447 return BAD_VALUE;
448
449 // get size
450 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
451 if (keySizeZeroTerminated > UINT16_MAX) {
452 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
453 return INVALID_OPERATION;
454 }
455 const uint16_t version = 0;
Andy Hung1efc9c62019-12-03 13:43:33 -0800456 const uint32_t header_size =
457 sizeof(uint32_t) // total size
458 + sizeof(header_size) // header size
459 + sizeof(version) // encoding version
460 + sizeof(uint16_t) // key size
Andy Hung3253f2d2019-10-21 14:50:07 -0700461 + keySizeZeroTerminated // key, zero terminated
Andy Hung1efc9c62019-12-03 13:43:33 -0800462 + sizeof(int32_t) // pid
463 + sizeof(int32_t) // uid
464 + sizeof(int64_t) // timestamp
Andy Hung3253f2d2019-10-21 14:50:07 -0700465 ;
466
Andy Hung1efc9c62019-12-03 13:43:33 -0800467 uint32_t size = header_size
Andy Hung3253f2d2019-10-21 14:50:07 -0700468 + sizeof(uint32_t) // # properties
469 ;
Andy Hung47e58d62019-12-06 18:40:19 -0800470 for (auto &prop : *this) {
471 const size_t propSize = prop.getByteStringSize();
Andy Hung1efc9c62019-12-03 13:43:33 -0800472 if (propSize > UINT16_MAX) {
Andy Hung47e58d62019-12-06 18:40:19 -0800473 ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize);
Andy Hung3253f2d2019-10-21 14:50:07 -0700474 return INVALID_OPERATION;
475 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800476 if (__builtin_add_overflow(size, propSize, &size)) {
Andy Hung47e58d62019-12-06 18:40:19 -0800477 ALOGW("%s: item size overflow at property %s", __func__, prop.getName());
Andy Hung1efc9c62019-12-03 13:43:33 -0800478 return INVALID_OPERATION;
479 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700480 }
481
Andy Hung1efc9c62019-12-03 13:43:33 -0800482 // since we fill every byte in the buffer (there is no padding),
483 // malloc is used here instead of calloc.
484 char * const build = (char *)malloc(size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700485 if (build == nullptr) return NO_MEMORY;
486
487 char *filling = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800488 char *buildmax = build + size;
489 if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
490 || insert(header_size, &filling, buildmax) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700491 || insert(version, &filling, buildmax) != NO_ERROR
492 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
493 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
494 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
495 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
496 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
Andy Hung47e58d62019-12-06 18:40:19 -0800497 || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800498 ALOGE("%s:could not write header", __func__); // shouldn't happen
Andy Hung3253f2d2019-10-21 14:50:07 -0700499 free(build);
500 return INVALID_OPERATION;
501 }
Andy Hung47e58d62019-12-06 18:40:19 -0800502 for (auto &prop : *this) {
503 if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700504 free(build);
Andy Hung1efc9c62019-12-03 13:43:33 -0800505 // shouldn't happen
Andy Hung47e58d62019-12-06 18:40:19 -0800506 ALOGE("%s:could not write prop %s", __func__, prop.getName());
Andy Hung3253f2d2019-10-21 14:50:07 -0700507 return INVALID_OPERATION;
508 }
509 }
510
511 if (filling != buildmax) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800512 ALOGE("%s: problems populating; wrote=%d planned=%d",
513 __func__, (int)(filling - build), (int)size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700514 free(build);
515 return INVALID_OPERATION;
516 }
517 *pbuffer = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800518 *plength = size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700519 return NO_ERROR;
520}
521
Ray Essickf27e9872019-12-07 06:28:46 -0800522status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
Andy Hung3253f2d2019-10-21 14:50:07 -0700523{
524 if (bufferptr == nullptr) return BAD_VALUE;
525
526 const char *read = bufferptr;
527 const char *readend = bufferptr + length;
528
Andy Hung1efc9c62019-12-03 13:43:33 -0800529 uint32_t size;
530 uint32_t header_size;
531 uint16_t version;
532 uint16_t key_size;
Andy Hungb7aadb32019-12-09 19:40:42 -0800533 std::string key;
Andy Hung3253f2d2019-10-21 14:50:07 -0700534 int32_t pid;
535 int32_t uid;
536 int64_t timestamp;
537 uint32_t propCount;
Andy Hung1efc9c62019-12-03 13:43:33 -0800538 if (extract(&size, &read, readend) != NO_ERROR
539 || extract(&header_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700540 || extract(&version, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800541 || extract(&key_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700542 || extract(&key, &read, readend) != NO_ERROR
543 || extract(&pid, &read, readend) != NO_ERROR
544 || extract(&uid, &read, readend) != NO_ERROR
545 || extract(&timestamp, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800546 || size > length
Andy Hungb7aadb32019-12-09 19:40:42 -0800547 || key.size() + 1 != key_size
Andy Hung1efc9c62019-12-03 13:43:33 -0800548 || header_size > size) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800549 ALOGW("%s: invalid header", __func__);
Andy Hung3253f2d2019-10-21 14:50:07 -0700550 return INVALID_OPERATION;
551 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800552 mKey = std::move(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700553 const size_t pos = read - bufferptr;
Andy Hung1efc9c62019-12-03 13:43:33 -0800554 if (pos > header_size) {
555 ALOGW("%s: invalid header pos:%zu > header_size:%u",
556 __func__, pos, header_size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700557 return INVALID_OPERATION;
Andy Hung1efc9c62019-12-03 13:43:33 -0800558 } else if (pos < header_size) {
559 ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
560 __func__, pos, header_size);
561 read += (header_size - pos);
Andy Hung3253f2d2019-10-21 14:50:07 -0700562 }
563 if (extract(&propCount, &read, readend) != NO_ERROR) {
564 ALOGD("%s: cannot read prop count", __func__);
565 return INVALID_OPERATION;
566 }
567 mPid = pid;
568 mUid = uid;
569 mTimestamp = timestamp;
570 for (size_t i = 0; i < propCount; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800571 Prop prop;
572 if (prop.readFromByteString(&read, readend) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800573 ALOGW("%s: cannot read prop %zu", __func__, i);
Andy Hung3253f2d2019-10-21 14:50:07 -0700574 return INVALID_OPERATION;
575 }
Andy Hung47e58d62019-12-06 18:40:19 -0800576 mProps[prop.getName()] = std::move(prop);
Andy Hung3253f2d2019-10-21 14:50:07 -0700577 }
578 return NO_ERROR;
579}
580
Ray Essickf27e9872019-12-07 06:28:46 -0800581status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
Andy Hung3253f2d2019-10-21 14:50:07 -0700582{
583 const char *key = data.readCString();
584 if (key == nullptr) return BAD_VALUE;
585 int32_t type;
586 status_t status = data.readInt32(&type);
587 if (status != NO_ERROR) return status;
588 switch (type) {
Andy Hungb7aadb32019-12-09 19:40:42 -0800589 case mediametrics::kTypeInt32: {
590 int32_t value;
591 status = data.readInt32(&value);
592 if (status != NO_ERROR) return status;
593 mElem = value;
594 } break;
595 case mediametrics::kTypeInt64: {
596 int64_t value;
597 status = data.readInt64(&value);
598 if (status != NO_ERROR) return status;
599 mElem = value;
600 } break;
601 case mediametrics::kTypeDouble: {
602 double value;
603 status = data.readDouble(&value);
604 if (status != NO_ERROR) return status;
605 mElem = value;
606 } break;
Andy Hung47e58d62019-12-06 18:40:19 -0800607 case mediametrics::kTypeCString: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700608 const char *s = data.readCString();
609 if (s == nullptr) return BAD_VALUE;
Andy Hungb7aadb32019-12-09 19:40:42 -0800610 mElem = s;
611 } break;
Andy Hung47e58d62019-12-06 18:40:19 -0800612 case mediametrics::kTypeRate: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700613 std::pair<int64_t, int64_t> rate;
614 status = data.readInt64(&rate.first)
615 ?: data.readInt64(&rate.second);
Andy Hungb7aadb32019-12-09 19:40:42 -0800616 if (status != NO_ERROR) return status;
617 mElem = rate;
618 } break;
619 case mediametrics::kTypeNone: {
620 mElem = std::monostate{};
621 } break;
Andy Hung3253f2d2019-10-21 14:50:07 -0700622 default:
Andy Hungb7aadb32019-12-09 19:40:42 -0800623 ALOGE("%s: reading bad item type: %d", __func__, type);
Andy Hung3253f2d2019-10-21 14:50:07 -0700624 return BAD_VALUE;
625 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800626 setName(key);
627 return NO_ERROR;
Andy Hung3253f2d2019-10-21 14:50:07 -0700628}
629
Ray Essickf27e9872019-12-07 06:28:46 -0800630status_t mediametrics::Item::Prop::readFromByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700631 const char **bufferpptr, const char *bufferptrmax)
632{
633 uint16_t len;
Andy Hungb7aadb32019-12-09 19:40:42 -0800634 std::string name;
Andy Hung3253f2d2019-10-21 14:50:07 -0700635 uint8_t type;
636 status_t status = extract(&len, bufferpptr, bufferptrmax)
637 ?: extract(&type, bufferpptr, bufferptrmax)
638 ?: extract(&name, bufferpptr, bufferptrmax);
639 if (status != NO_ERROR) return status;
Andy Hungb7aadb32019-12-09 19:40:42 -0800640 switch (type) {
641 case mediametrics::kTypeInt32: {
642 int32_t value;
643 status = extract(&value, bufferpptr, bufferptrmax);
644 if (status != NO_ERROR) return status;
645 mElem = value;
646 } break;
647 case mediametrics::kTypeInt64: {
648 int64_t value;
649 status = extract(&value, bufferpptr, bufferptrmax);
650 if (status != NO_ERROR) return status;
651 mElem = value;
652 } break;
653 case mediametrics::kTypeDouble: {
654 double value;
655 status = extract(&value, bufferpptr, bufferptrmax);
656 if (status != NO_ERROR) return status;
657 mElem = value;
658 } break;
659 case mediametrics::kTypeRate: {
660 std::pair<int64_t, int64_t> value;
661 status = extract(&value.first, bufferpptr, bufferptrmax)
662 ?: extract(&value.second, bufferpptr, bufferptrmax);
663 if (status != NO_ERROR) return status;
664 mElem = value;
665 } break;
666 case mediametrics::kTypeCString: {
667 std::string value;
668 status = extract(&value, bufferpptr, bufferptrmax);
669 if (status != NO_ERROR) return status;
670 mElem = std::move(value);
671 } break;
672 case mediametrics::kTypeNone: {
673 mElem = std::monostate{};
674 } break;
Andy Hung3253f2d2019-10-21 14:50:07 -0700675 default:
Andy Hung3253f2d2019-10-21 14:50:07 -0700676 ALOGE("%s: found bad prop type: %d, name %s",
Andy Hungb7aadb32019-12-09 19:40:42 -0800677 __func__, (int)type, mName.c_str()); // no payload sent
Andy Hung3253f2d2019-10-21 14:50:07 -0700678 return BAD_VALUE;
679 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800680 mName = name;
681 return NO_ERROR;
Andy Hung3253f2d2019-10-21 14:50:07 -0700682}
683
Ray Essickf27e9872019-12-07 06:28:46 -0800684} // namespace android::mediametrics