blob: 98158d24f0fa8471e79949704016af2f86accc5a [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>
28#include <utils/Errors.h>
29#include <utils/Log.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <utils/SortedVector.h>
31#include <utils/threads.h>
32
Ray Essick3938dc62016-11-01 08:56:56 -070033#include <binder/IServiceManager.h>
Ray Essickf27e9872019-12-07 06:28:46 -080034#include <media/IMediaMetricsService.h>
35#include <media/MediaMetricsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070036#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070037
Andy Hung1efc9c62019-12-03 13:43:33 -080038// Max per-property string size before truncation in toString().
39// Do not make too large, as this is used for dumpsys purposes.
40static constexpr size_t kMaxPropertyStringSize = 4096;
41
Ray Essickf27e9872019-12-07 06:28:46 -080042namespace android::mediametrics {
Ray Essick3938dc62016-11-01 08:56:56 -070043
44#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080045#define DEBUG_API 0
46#define DEBUG_ALLOCATIONS 0
47
48// after this many failed attempts, we stop trying [from this process] and just say that
49// the service is off.
50#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070051
Ray Essickf27e9872019-12-07 06:28:46 -080052mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
53 mediametrics::Item *item = (android::mediametrics::Item *) handle;
Ray Essickbf536ac2019-08-26 11:04:28 -070054 return item;
55}
56
Ray Essickf27e9872019-12-07 06:28:46 -080057mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
Ray Essickbf536ac2019-08-26 11:04:28 -070058 mediametrics_handle_t handle = (mediametrics_handle_t) item;
59 return handle;
60}
61
Ray Essickf27e9872019-12-07 06:28:46 -080062mediametrics::Item::~Item() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080063 if (DEBUG_ALLOCATIONS) {
Ray Essickf27e9872019-12-07 06:28:46 -080064 ALOGD("Destroy mediametrics::Item @ %p", this);
Ray Essickb5fac8e2016-12-12 11:33:56 -080065 }
Ray Essick3938dc62016-11-01 08:56:56 -070066 clear();
67}
68
Ray Essickf27e9872019-12-07 06:28:46 -080069void mediametrics::Item::clear() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080070
71 // clean allocated storage from key
72 mKey.clear();
73
74 // clean attributes
75 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -070076 for (size_t i = 0 ; i < mPropCount; i++ ) {
Andy Hungaeef7882019-10-18 15:18:14 -070077 mProps[i].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -080078 }
79 // the attribute records themselves
80 if (mProps != NULL) {
81 free(mProps);
82 mProps = NULL;
83 }
84 mPropSize = 0;
85 mPropCount = 0;
86
87 return;
88}
89
90// make a deep copy of myself
Ray Essickf27e9872019-12-07 06:28:46 -080091mediametrics::Item *mediametrics::Item::dup() {
92 mediametrics::Item *dst = new mediametrics::Item(this->mKey);
Ray Essickb5fac8e2016-12-12 11:33:56 -080093
94 if (dst != NULL) {
95 // key as part of constructor
96 dst->mPid = this->mPid;
97 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -070098 dst->mPkgName = this->mPkgName;
99 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800100 dst->mTimestamp = this->mTimestamp;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800101
102 // properties aka attributes
103 dst->growProps(this->mPropCount);
104 for(size_t i=0;i<mPropCount;i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700105 dst->mProps[i] = this->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800106 }
107 dst->mPropCount = this->mPropCount;
108 }
109
110 return dst;
111}
112
Ray Essickf27e9872019-12-07 06:28:46 -0800113mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
Ray Essick3938dc62016-11-01 08:56:56 -0700114 mTimestamp = ts;
115 return *this;
116}
117
Ray Essickf27e9872019-12-07 06:28:46 -0800118nsecs_t mediametrics::Item::getTimestamp() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700119 return mTimestamp;
120}
121
Ray Essickf27e9872019-12-07 06:28:46 -0800122mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
Ray Essick3938dc62016-11-01 08:56:56 -0700123 mPid = pid;
124 return *this;
125}
126
Ray Essickf27e9872019-12-07 06:28:46 -0800127pid_t mediametrics::Item::getPid() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700128 return mPid;
129}
130
Ray Essickf27e9872019-12-07 06:28:46 -0800131mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
Ray Essick3938dc62016-11-01 08:56:56 -0700132 mUid = uid;
133 return *this;
134}
135
Ray Essickf27e9872019-12-07 06:28:46 -0800136uid_t mediametrics::Item::getUid() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700137 return mUid;
138}
139
Ray Essickf27e9872019-12-07 06:28:46 -0800140mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700141 mPkgName = pkgName;
142 return *this;
143}
144
Ray Essickf27e9872019-12-07 06:28:46 -0800145mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700146 mPkgVersionCode = pkgVersionCode;
147 return *this;
148}
149
Ray Essickf27e9872019-12-07 06:28:46 -0800150int64_t mediametrics::Item::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700151 return mPkgVersionCode;
152}
153
Ray Essickb5fac8e2016-12-12 11:33:56 -0800154
155// find the proper entry in the list
Ray Essickf27e9872019-12-07 06:28:46 -0800156size_t mediametrics::Item::findPropIndex(const char *name) const
Ray Essickb5fac8e2016-12-12 11:33:56 -0800157{
158 size_t i = 0;
159 for (; i < mPropCount; i++) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700160 if (mProps[i].isNamed(name)) break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800161 }
162 return i;
163}
164
Ray Essickf27e9872019-12-07 06:28:46 -0800165mediametrics::Item::Prop *mediametrics::Item::findProp(const char *name) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700166 const size_t i = findPropIndex(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800167 if (i < mPropCount) {
168 return &mProps[i];
169 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700170 return nullptr;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800171}
172
Ray Essick9ce18f72018-05-07 15:54:30 -0700173// consider this "find-or-allocate".
174// caller validates type and uses clearPropValue() accordingly
Ray Essickf27e9872019-12-07 06:28:46 -0800175mediametrics::Item::Prop *mediametrics::Item::allocateProp(const char *name) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700176 const size_t i = findPropIndex(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800177 if (i < mPropCount) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700178 return &mProps[i]; // already have it, return
Ray Essickb5fac8e2016-12-12 11:33:56 -0800179 }
180
Andy Hung3253f2d2019-10-21 14:50:07 -0700181 Prop *prop = allocateProp(); // get a new prop
182 if (prop == nullptr) return nullptr;
183 prop->setName(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800184 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700185}
186
Ray Essickf27e9872019-12-07 06:28:46 -0800187mediametrics::Item::Prop *mediametrics::Item::allocateProp() {
Andy Hung3253f2d2019-10-21 14:50:07 -0700188 if (mPropCount == mPropSize && growProps() == false) {
189 ALOGE("%s: failed allocation for new properties", __func__);
190 return nullptr;
191 }
192 return &mProps[mPropCount++];
193}
194
Ray Essickf65f4212017-08-31 11:41:19 -0700195// used within the summarizers; return whether property existed
Ray Essickf27e9872019-12-07 06:28:46 -0800196bool mediametrics::Item::removeProp(const char *name) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700197 const size_t i = findPropIndex(name);
Ray Essickf65f4212017-08-31 11:41:19 -0700198 if (i < mPropCount) {
Andy Hungaeef7882019-10-18 15:18:14 -0700199 mProps[i].clear();
Ray Essickf65f4212017-08-31 11:41:19 -0700200 if (i != mPropCount-1) {
201 // in the middle, bring last one down to fill gap
Andy Hungaeef7882019-10-18 15:18:14 -0700202 mProps[i].swap(mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700203 }
204 mPropCount--;
205 return true;
206 }
207 return false;
208}
209
Ray Essick3938dc62016-11-01 08:56:56 -0700210// remove indicated keys and their values
211// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800212size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700213 size_t zapped = 0;
214 for (size_t i = 0; i < n; ++i) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800215 const char *name = attrs[i];
Andy Hung3253f2d2019-10-21 14:50:07 -0700216 size_t j = findPropIndex(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800217 if (j >= mPropCount) {
218 // not there
219 continue;
Andy Hung3253f2d2019-10-21 14:50:07 -0700220 } else if (j + 1 == mPropCount) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800221 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700222 zapped++;
Andy Hungaeef7882019-10-18 15:18:14 -0700223 mProps[j].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800224 mPropCount--;
225 } else {
226 // in the middle, bring last one down and shorten
227 zapped++;
Andy Hungaeef7882019-10-18 15:18:14 -0700228 mProps[j].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800229 mProps[j] = mProps[mPropCount-1];
230 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700231 }
232 }
233 return zapped;
234}
235
236// remove any keys NOT in the provided list
237// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800238size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700239 std::set<std::string> check(attrs, attrs + n);
240 size_t zapped = 0;
241 for (size_t j = 0; j < mPropCount;) {
242 if (check.find(mProps[j].getName()) != check.end()) {
243 ++j;
244 continue;
245 }
246 if (j + 1 == mPropCount) {
247 // last one, shorten
248 zapped++;
249 mProps[j].clear();
250 mPropCount--;
251 break;
252 } else {
253 // in the middle, bring last one down and shorten
254 zapped++;
255 mProps[j].clear();
256 mProps[j] = mProps[mPropCount-1];
257 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700258 }
259 }
260 return zapped;
261}
262
Ray Essickf27e9872019-12-07 06:28:46 -0800263bool mediametrics::Item::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800264{
265 if (increment <= 0) {
266 increment = kGrowProps;
267 }
268 int nsize = mPropSize + increment;
269 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
270
271 if (ni != NULL) {
272 for (int i = mPropSize; i < nsize; i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700273 new (&ni[i]) Prop(); // placement new
Ray Essickb5fac8e2016-12-12 11:33:56 -0800274 }
275 mProps = ni;
276 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700277 return true;
278 } else {
Ray Essickf27e9872019-12-07 06:28:46 -0800279 ALOGW("mediametrics::Item::growProps fails");
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700280 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800281 }
Ray Essick3938dc62016-11-01 08:56:56 -0700282}
283
284// Parcel / serialize things for binder calls
285//
286
Ray Essickf27e9872019-12-07 06:28:46 -0800287status_t mediametrics::Item::readFromParcel(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700288 int32_t version;
289 status_t status = data.readInt32(&version);
290 if (status != NO_ERROR) return status;
Ray Essickba8c4842019-01-18 11:35:33 -0800291
Andy Hung3253f2d2019-10-21 14:50:07 -0700292 switch (version) {
293 case 0:
294 return readFromParcel0(data);
295 default:
296 ALOGE("%s: unsupported parcel version: %d", __func__, version);
297 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800298 }
299}
300
Ray Essickf27e9872019-12-07 06:28:46 -0800301status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700302 const char *s = data.readCString();
303 mKey = s == nullptr ? "" : s;
304 int32_t pid, uid;
305 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
306 if (status != NO_ERROR) return status;
307 mPid = (pid_t)pid;
308 mUid = (uid_t)uid;
309 s = data.readCString();
310 mPkgName = s == nullptr ? "" : s;
311 int32_t count;
312 int64_t version, timestamp;
313 status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
314 if (status != NO_ERROR) return status;
315 if (count < 0) return BAD_VALUE;
316 mPkgVersionCode = version;
317 mTimestamp = timestamp;
Ray Essick3938dc62016-11-01 08:56:56 -0700318 for (int i = 0; i < count ; i++) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700319 Prop *prop = allocateProp();
320 status_t status = prop->readFromParcel(data);
321 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700322 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700323 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700324}
325
Ray Essickf27e9872019-12-07 06:28:46 -0800326status_t mediametrics::Item::writeToParcel(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700327 if (data == nullptr) return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800328
Andy Hung3253f2d2019-10-21 14:50:07 -0700329 const int32_t version = 0;
330 status_t status = data->writeInt32(version);
331 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700332
Andy Hung3253f2d2019-10-21 14:50:07 -0700333 switch (version) {
334 case 0:
335 return writeToParcel0(data);
336 default:
337 ALOGE("%s: unsupported parcel version: %d", __func__, version);
338 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800339 }
340}
341
Ray Essickf27e9872019-12-07 06:28:46 -0800342status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700343 status_t status =
344 data->writeCString(mKey.c_str())
345 ?: data->writeInt32(mPid)
346 ?: data->writeInt32(mUid)
347 ?: data->writeCString(mPkgName.c_str())
348 ?: data->writeInt64(mPkgVersionCode)
349 ?: data->writeInt64(mTimestamp);
350 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700351
Andy Hung3253f2d2019-10-21 14:50:07 -0700352 data->writeInt32((int32_t)mPropCount);
353 for (size_t i = 0 ; i < mPropCount; ++i) {
354 status = mProps[i].writeToParcel(data);
355 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700356 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700357 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700358}
359
Ray Essickf27e9872019-12-07 06:28:46 -0800360const char *mediametrics::Item::toCString() {
Ray Essick20147322018-11-17 09:08:39 -0800361 return toCString(PROTO_LAST);
362}
363
Ray Essickf27e9872019-12-07 06:28:46 -0800364const char * mediametrics::Item::toCString(int version) {
Ray Essick20147322018-11-17 09:08:39 -0800365 std::string val = toString(version);
366 return strdup(val.c_str());
367}
368
Ray Essickf27e9872019-12-07 06:28:46 -0800369std::string mediametrics::Item::toString() const {
Ray Essick5b77bd22018-01-23 16:11:06 -0800370 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700371}
Ray Essick3938dc62016-11-01 08:56:56 -0700372
Ray Essickf27e9872019-12-07 06:28:46 -0800373std::string mediametrics::Item::toString(int version) const {
Ray Essick783bd0d2018-01-11 11:10:35 -0800374 std::string result;
Andy Hung1efc9c62019-12-03 13:43:33 -0800375 char buffer[kMaxPropertyStringSize];
Ray Essick3938dc62016-11-01 08:56:56 -0700376
Andy Hung1efc9c62019-12-03 13:43:33 -0800377 snprintf(buffer, sizeof(buffer), "[%d:%s:%d:%d:%lld:%s:%zu:",
378 version, mKey.c_str(), mPid, mUid, (long long)mTimestamp,
379 mPkgName.c_str(), mPropCount);
Ray Essickf65f4212017-08-31 11:41:19 -0700380 result.append(buffer);
Andy Hung1efc9c62019-12-03 13:43:33 -0800381 for (size_t i = 0 ; i < mPropCount; ++i) {
Andy Hungaeef7882019-10-18 15:18:14 -0700382 mProps[i].toString(buffer, sizeof(buffer));
383 result.append(buffer);
Ray Essick3938dc62016-11-01 08:56:56 -0700384 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800385 result.append("]");
Ray Essick3938dc62016-11-01 08:56:56 -0700386 return result;
387}
388
389// for the lazy, we offer methods that finds the service and
390// calls the appropriate daemon
Ray Essickf27e9872019-12-07 06:28:46 -0800391bool mediametrics::Item::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700392 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Ray Essickf27e9872019-12-07 06:28:46 -0800393 sp<IMediaMetricsService> svc = getInstance();
Ray Essick3938dc62016-11-01 08:56:56 -0700394 if (svc != NULL) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700395 status_t status = svc->submit(this);
396 if (status != NO_ERROR) {
397 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick2ab3c432017-10-02 09:29:49 -0700398 return false;
399 }
Ray Essick3938dc62016-11-01 08:56:56 -0700400 return true;
401 } else {
402 return false;
403 }
404}
405
Ray Essick3938dc62016-11-01 08:56:56 -0700406//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800407bool BaseItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700408 // completely skip logging from certain UIDs. We do this here
409 // to avoid the multi-second timeouts while we learn that
410 // sepolicy will not let us find the service.
411 // We do this only for a select set of UIDs
412 // The sepolicy protection is still in place, we just want a faster
413 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700414
Andy Hunga87e69c2019-10-18 10:07:40 -0700415 // This is checked only once in the lifetime of the process.
416 const uid_t uid = getuid();
417 switch (uid) {
418 case AID_RADIO: // telephony subsystem, RIL
419 return false;
420 }
421
Ray Essickf27e9872019-12-07 06:28:46 -0800422 int enabled = property_get_int32(Item::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700423 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800424 enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700425 }
426 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800427 enabled = Item::EnabledProperty_default;
Ray Essick3938dc62016-11-01 08:56:56 -0700428 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700429 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700430}
431
Ray Essick2ab3c432017-10-02 09:29:49 -0700432// monitor health of our connection to the metrics service
433class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
434 virtual void binderDied(const wp<IBinder> &) {
435 ALOGW("Reacquire service connection on next request");
Andy Hung1efc9c62019-12-03 13:43:33 -0800436 BaseItem::dropInstance();
Ray Essick2ab3c432017-10-02 09:29:49 -0700437 }
438};
439
Andy Hunga87e69c2019-10-18 10:07:40 -0700440static sp<MediaMetricsDeathNotifier> sNotifier;
441// static
Ray Essickf27e9872019-12-07 06:28:46 -0800442sp<IMediaMetricsService> BaseItem::sMediaMetricsService;
Andy Hunga87e69c2019-10-18 10:07:40 -0700443static std::mutex sServiceMutex;
444static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700445
446// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800447void BaseItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700448 std::lock_guard _l(sServiceMutex);
449 sRemainingBindAttempts = SVC_TRIES;
Ray Essickf27e9872019-12-07 06:28:46 -0800450 sMediaMetricsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700451}
452
Andy Hung1efc9c62019-12-03 13:43:33 -0800453// static
454bool BaseItem::submitBuffer(const char *buffer, size_t size) {
455/*
Ray Essickf27e9872019-12-07 06:28:46 -0800456 mediametrics::Item item;
Andy Hung1efc9c62019-12-03 13:43:33 -0800457 status_t status = item.readFromByteString(buffer, size);
458 ALOGD("%s: status:%d, size:%zu, item:%s", __func__, status, size, item.toString().c_str());
459 return item.selfrecord();
460 */
461
462 ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
Ray Essickf27e9872019-12-07 06:28:46 -0800463 sp<IMediaMetricsService> svc = getInstance();
Andy Hung1efc9c62019-12-03 13:43:33 -0800464 if (svc != nullptr) {
465 const status_t status = svc->submitBuffer(buffer, size);
466 if (status != NO_ERROR) {
467 ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
468 return false;
469 }
470 return true;
471 }
472 return false;
473}
474
Ray Essick3938dc62016-11-01 08:56:56 -0700475//static
Ray Essickf27e9872019-12-07 06:28:46 -0800476sp<IMediaMetricsService> BaseItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800477 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700478 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700479
480 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700481 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
482 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700483 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700484 std::lock_guard _l(sServiceMutex);
485 // think of remainingBindAttempts as telling us whether service == nullptr because
486 // (1) we haven't tried to initialize it yet
487 // (2) we've tried to initialize it, but failed.
Ray Essickf27e9872019-12-07 06:28:46 -0800488 if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700489 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700490 sp<IServiceManager> sm = defaultServiceManager();
491 if (sm != nullptr) {
492 sp<IBinder> binder = sm->getService(String16(servicename));
493 if (binder != nullptr) {
Ray Essickf27e9872019-12-07 06:28:46 -0800494 sMediaMetricsService = interface_cast<IMediaMetricsService>(binder);
Andy Hunga87e69c2019-10-18 10:07:40 -0700495 sNotifier = new MediaMetricsDeathNotifier();
496 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700497 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700498 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700499 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700500 } else {
501 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700502 }
Ray Essickf27e9872019-12-07 06:28:46 -0800503 if (sMediaMetricsService == nullptr) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700504 if (sRemainingBindAttempts > 0) {
505 sRemainingBindAttempts--;
506 }
507 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
508 __func__, servicename, badness);
509 }
Ray Essick3938dc62016-11-01 08:56:56 -0700510 }
Ray Essickf27e9872019-12-07 06:28:46 -0800511 return sMediaMetricsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700512}
513
Andy Hung1efc9c62019-12-03 13:43:33 -0800514
Ray Essick3938dc62016-11-01 08:56:56 -0700515// merge the info from 'incoming' into this record.
516// we finish with a union of this+incoming and special handling for collisions
Ray Essickf27e9872019-12-07 06:28:46 -0800517bool mediametrics::Item::merge(mediametrics::Item *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700518
519 // if I don't have key or session id, take them from incoming
520 // 'this' should never be missing both of them...
521 if (mKey.empty()) {
522 mKey = incoming->mKey;
Ray Essick3938dc62016-11-01 08:56:56 -0700523 }
524
Ray Essick3938dc62016-11-01 08:56:56 -0700525 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800526 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700527 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800528 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800529 const char *p = iprop->mName;
530 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700531
532 // should ignore a zero length name...
533 if (len == 0) {
534 continue;
535 }
536
537 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700538
Ray Essickb5fac8e2016-12-12 11:33:56 -0800539 if (oprop == NULL) {
540 // no oprop, so we insert the new one
541 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700542 if (oprop != NULL) {
Andy Hungaeef7882019-10-18 15:18:14 -0700543 *oprop = *iprop;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700544 } else {
545 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800546 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700547 } else {
Andy Hungaeef7882019-10-18 15:18:14 -0700548 *oprop = *iprop;
Ray Essick3938dc62016-11-01 08:56:56 -0700549 }
550 }
551
552 // not sure when we'd return false...
553 return true;
554}
555
Andy Hung3253f2d2019-10-21 14:50:07 -0700556namespace {
Ray Essickba8c4842019-01-18 11:35:33 -0800557
Andy Hung3253f2d2019-10-21 14:50:07 -0700558template <typename T>
559status_t insert(const T& val, char **bufferpptr, char *bufferptrmax)
560{
561 const size_t size = sizeof(val);
562 if (*bufferpptr + size > bufferptrmax) {
563 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
564 return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800565 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700566 memcpy(*bufferpptr, &val, size);
567 *bufferpptr += size;
568 return NO_ERROR;
Ray Essickba8c4842019-01-18 11:35:33 -0800569}
570
Andy Hung3253f2d2019-10-21 14:50:07 -0700571template <>
572status_t insert(const char * const& val, char **bufferpptr, char *bufferptrmax)
Andy Hungaeef7882019-10-18 15:18:14 -0700573{
Andy Hung3253f2d2019-10-21 14:50:07 -0700574 const size_t size = strlen(val) + 1;
575 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
576 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
577 return BAD_VALUE;
578 }
579 memcpy(*bufferpptr, val, size);
580 *bufferpptr += size;
581 return NO_ERROR;
582}
583
584template <>
585 __unused
586status_t insert(char * const& val, char **bufferpptr, char *bufferptrmax)
587{
588 return insert((const char *)val, bufferpptr, bufferptrmax);
589}
590
591template <typename T>
592status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax)
593{
594 const size_t size = sizeof(*val);
595 if (*bufferpptr + size > bufferptrmax) {
596 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
597 return BAD_VALUE;
598 }
599 memcpy(val, *bufferpptr, size);
600 *bufferpptr += size;
601 return NO_ERROR;
602}
603
604template <>
605status_t extract(char **val, const char **bufferpptr, const char *bufferptrmax)
606{
607 const char *ptr = *bufferpptr;
608 while (*ptr != 0) {
609 if (ptr >= bufferptrmax) {
610 ALOGE("%s: buffer exceeded", __func__);
Andy Hung1efc9c62019-12-03 13:43:33 -0800611 return BAD_VALUE;
Andy Hung3253f2d2019-10-21 14:50:07 -0700612 }
613 ++ptr;
614 }
615 const size_t size = (ptr - *bufferpptr) + 1;
616 *val = (char *)malloc(size);
617 memcpy(*val, *bufferpptr, size);
618 *bufferpptr += size;
619 return NO_ERROR;
620}
621
622} // namespace
623
Ray Essickf27e9872019-12-07 06:28:46 -0800624status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700625{
626 if (pbuffer == nullptr || plength == nullptr)
627 return BAD_VALUE;
628
629 // get size
630 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
631 if (keySizeZeroTerminated > UINT16_MAX) {
632 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
633 return INVALID_OPERATION;
634 }
635 const uint16_t version = 0;
Andy Hung1efc9c62019-12-03 13:43:33 -0800636 const uint32_t header_size =
637 sizeof(uint32_t) // total size
638 + sizeof(header_size) // header size
639 + sizeof(version) // encoding version
640 + sizeof(uint16_t) // key size
Andy Hung3253f2d2019-10-21 14:50:07 -0700641 + keySizeZeroTerminated // key, zero terminated
Andy Hung1efc9c62019-12-03 13:43:33 -0800642 + sizeof(int32_t) // pid
643 + sizeof(int32_t) // uid
644 + sizeof(int64_t) // timestamp
Andy Hung3253f2d2019-10-21 14:50:07 -0700645 ;
646
Andy Hung1efc9c62019-12-03 13:43:33 -0800647 uint32_t size = header_size
Andy Hung3253f2d2019-10-21 14:50:07 -0700648 + sizeof(uint32_t) // # properties
649 ;
650 for (size_t i = 0 ; i < mPropCount; ++i) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800651 const size_t propSize = mProps[i].getByteStringSize();
652 if (propSize > UINT16_MAX) {
653 ALOGW("%s: prop %zu size %zu too large", __func__, i, propSize);
Andy Hung3253f2d2019-10-21 14:50:07 -0700654 return INVALID_OPERATION;
655 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800656 if (__builtin_add_overflow(size, propSize, &size)) {
657 ALOGW("%s: item size overflow at property %zu", __func__, i);
658 return INVALID_OPERATION;
659 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700660 }
661
Andy Hung1efc9c62019-12-03 13:43:33 -0800662 // since we fill every byte in the buffer (there is no padding),
663 // malloc is used here instead of calloc.
664 char * const build = (char *)malloc(size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700665 if (build == nullptr) return NO_MEMORY;
666
667 char *filling = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800668 char *buildmax = build + size;
669 if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
670 || insert(header_size, &filling, buildmax) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700671 || insert(version, &filling, buildmax) != NO_ERROR
672 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
673 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
674 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
675 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
676 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
677 || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800678 ALOGE("%s:could not write header", __func__); // shouldn't happen
Andy Hung3253f2d2019-10-21 14:50:07 -0700679 free(build);
680 return INVALID_OPERATION;
681 }
682 for (size_t i = 0 ; i < mPropCount; ++i) {
683 if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) {
684 free(build);
Andy Hung1efc9c62019-12-03 13:43:33 -0800685 // shouldn't happen
686 ALOGE("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
Andy Hung3253f2d2019-10-21 14:50:07 -0700687 return INVALID_OPERATION;
688 }
689 }
690
691 if (filling != buildmax) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800692 ALOGE("%s: problems populating; wrote=%d planned=%d",
693 __func__, (int)(filling - build), (int)size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700694 free(build);
695 return INVALID_OPERATION;
696 }
697 *pbuffer = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800698 *plength = size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700699 return NO_ERROR;
700}
701
Ray Essickf27e9872019-12-07 06:28:46 -0800702status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
Andy Hung3253f2d2019-10-21 14:50:07 -0700703{
704 if (bufferptr == nullptr) return BAD_VALUE;
705
706 const char *read = bufferptr;
707 const char *readend = bufferptr + length;
708
Andy Hung1efc9c62019-12-03 13:43:33 -0800709 uint32_t size;
710 uint32_t header_size;
711 uint16_t version;
712 uint16_t key_size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700713 char *key = nullptr;
714 int32_t pid;
715 int32_t uid;
716 int64_t timestamp;
717 uint32_t propCount;
Andy Hung1efc9c62019-12-03 13:43:33 -0800718 if (extract(&size, &read, readend) != NO_ERROR
719 || extract(&header_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700720 || extract(&version, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800721 || extract(&key_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700722 || extract(&key, &read, readend) != NO_ERROR
723 || extract(&pid, &read, readend) != NO_ERROR
724 || extract(&uid, &read, readend) != NO_ERROR
725 || extract(&timestamp, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800726 || size > length
727 || strlen(key) + 1 != key_size
728 || header_size > size) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700729 free(key);
Andy Hung1efc9c62019-12-03 13:43:33 -0800730 ALOGW("%s: invalid header", __func__);
Andy Hung3253f2d2019-10-21 14:50:07 -0700731 return INVALID_OPERATION;
732 }
733 mKey = key;
734 free(key);
735 const size_t pos = read - bufferptr;
Andy Hung1efc9c62019-12-03 13:43:33 -0800736 if (pos > header_size) {
737 ALOGW("%s: invalid header pos:%zu > header_size:%u",
738 __func__, pos, header_size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700739 return INVALID_OPERATION;
Andy Hung1efc9c62019-12-03 13:43:33 -0800740 } else if (pos < header_size) {
741 ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
742 __func__, pos, header_size);
743 read += (header_size - pos);
Andy Hung3253f2d2019-10-21 14:50:07 -0700744 }
745 if (extract(&propCount, &read, readend) != NO_ERROR) {
746 ALOGD("%s: cannot read prop count", __func__);
747 return INVALID_OPERATION;
748 }
749 mPid = pid;
750 mUid = uid;
751 mTimestamp = timestamp;
752 for (size_t i = 0; i < propCount; ++i) {
753 Prop *prop = allocateProp();
754 if (prop->readFromByteString(&read, readend) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800755 ALOGW("%s: cannot read prop %zu", __func__, i);
Andy Hung3253f2d2019-10-21 14:50:07 -0700756 return INVALID_OPERATION;
757 }
758 }
759 return NO_ERROR;
760}
761
Ray Essickf27e9872019-12-07 06:28:46 -0800762status_t mediametrics::Item::Prop::writeToParcel(Parcel *data) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700763{
Andy Hungaeef7882019-10-18 15:18:14 -0700764 switch (mType) {
765 case kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700766 return data->writeCString(mName)
767 ?: data->writeInt32(mType)
768 ?: data->writeInt32(u.int32Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700769 case kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700770 return data->writeCString(mName)
771 ?: data->writeInt32(mType)
772 ?: data->writeInt64(u.int64Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700773 case kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700774 return data->writeCString(mName)
775 ?: data->writeInt32(mType)
776 ?: data->writeDouble(u.doubleValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700777 case kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700778 return data->writeCString(mName)
779 ?: data->writeInt32(mType)
780 ?: data->writeInt64(u.rate.first)
781 ?: data->writeInt64(u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700782 case kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700783 return data->writeCString(mName)
784 ?: data->writeInt32(mType)
785 ?: data->writeCString(u.CStringValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700786 default:
787 ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
Andy Hung3253f2d2019-10-21 14:50:07 -0700788 return BAD_VALUE;
Andy Hungaeef7882019-10-18 15:18:14 -0700789 }
790}
791
Ray Essickf27e9872019-12-07 06:28:46 -0800792status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
Andy Hung3253f2d2019-10-21 14:50:07 -0700793{
794 const char *key = data.readCString();
795 if (key == nullptr) return BAD_VALUE;
796 int32_t type;
797 status_t status = data.readInt32(&type);
798 if (status != NO_ERROR) return status;
799 switch (type) {
800 case kTypeInt32:
801 status = data.readInt32(&u.int32Value);
802 break;
803 case kTypeInt64:
804 status = data.readInt64(&u.int64Value);
805 break;
806 case kTypeDouble:
807 status = data.readDouble(&u.doubleValue);
808 break;
809 case kTypeCString: {
810 const char *s = data.readCString();
811 if (s == nullptr) return BAD_VALUE;
812 set(s);
813 break;
814 }
815 case kTypeRate: {
816 std::pair<int64_t, int64_t> rate;
817 status = data.readInt64(&rate.first)
818 ?: data.readInt64(&rate.second);
819 if (status == NO_ERROR) {
820 set(rate);
821 }
822 break;
823 }
824 default:
825 ALOGE("%s: reading bad item type: %d", __func__, mType);
826 return BAD_VALUE;
827 }
828 if (status == NO_ERROR) {
829 setName(key);
830 mType = (Type)type;
831 }
832 return status;
833}
834
Ray Essickf27e9872019-12-07 06:28:46 -0800835void mediametrics::Item::Prop::toString(char *buffer, size_t length) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700836{
Andy Hungaeef7882019-10-18 15:18:14 -0700837 switch (mType) {
838 case kTypeInt32:
839 snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
840 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800841 case mediametrics::Item::kTypeInt64:
Andy Hungaeef7882019-10-18 15:18:14 -0700842 snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value);
843 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800844 case mediametrics::Item::kTypeDouble:
Andy Hungaeef7882019-10-18 15:18:14 -0700845 snprintf(buffer, length, "%s=%e:", mName, u.doubleValue);
846 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800847 case mediametrics::Item::kTypeRate:
Andy Hungaeef7882019-10-18 15:18:14 -0700848 snprintf(buffer, length, "%s=%lld/%lld:",
Andy Hung3253f2d2019-10-21 14:50:07 -0700849 mName, (long long)u.rate.first, (long long)u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700850 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800851 case mediametrics::Item::kTypeCString:
Andy Hungaeef7882019-10-18 15:18:14 -0700852 // TODO sanitize string for ':' '='
853 snprintf(buffer, length, "%s=%s:", mName, u.CStringValue);
854 break;
855 default:
856 ALOGE("%s: bad item type: %d for %s", __func__, mType, mName);
857 if (length > 0) buffer[0] = 0;
858 break;
859 }
860}
861
Ray Essickf27e9872019-12-07 06:28:46 -0800862size_t mediametrics::Item::Prop::getByteStringSize() const
Andy Hung3253f2d2019-10-21 14:50:07 -0700863{
864 const size_t header =
865 sizeof(uint16_t) // length
866 + sizeof(uint8_t) // type
867 + strlen(mName) + 1; // mName + 0 termination
868 size_t payload = 0;
869 switch (mType) {
Ray Essickf27e9872019-12-07 06:28:46 -0800870 case mediametrics::Item::kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700871 payload = sizeof(u.int32Value);
872 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800873 case mediametrics::Item::kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700874 payload = sizeof(u.int64Value);
875 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800876 case mediametrics::Item::kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700877 payload = sizeof(u.doubleValue);
878 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800879 case mediametrics::Item::kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700880 payload = sizeof(u.rate.first) + sizeof(u.rate.second);
881 break;
Ray Essickf27e9872019-12-07 06:28:46 -0800882 case mediametrics::Item::kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700883 payload = strlen(u.CStringValue) + 1;
884 break;
885 default:
886 ALOGE("%s: found bad prop type: %d, name %s",
887 __func__, mType, mName); // no payload computed
888 break;
889 }
890 return header + payload;
891}
Ray Essick3938dc62016-11-01 08:56:56 -0700892
Andy Hung1efc9c62019-12-03 13:43:33 -0800893
Andy Hung3253f2d2019-10-21 14:50:07 -0700894// TODO: fold into a template later.
Andy Hung1efc9c62019-12-03 13:43:33 -0800895status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700896 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
897{
898 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
899 if (len > UINT16_MAX) return BAD_VALUE;
900 return insert((uint16_t)len, bufferpptr, bufferptrmax)
901 ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax)
902 ?: insert(name, bufferpptr, bufferptrmax)
903 ?: insert(value, bufferpptr, bufferptrmax);
904}
905
Andy Hung1efc9c62019-12-03 13:43:33 -0800906status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700907 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
908{
909 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
910 if (len > UINT16_MAX) return BAD_VALUE;
911 return insert((uint16_t)len, bufferpptr, bufferptrmax)
912 ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax)
913 ?: insert(name, bufferpptr, bufferptrmax)
914 ?: insert(value, bufferpptr, bufferptrmax);
915}
916
Andy Hung1efc9c62019-12-03 13:43:33 -0800917status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700918 const char *name, double value, char **bufferpptr, char *bufferptrmax)
919{
920 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
921 if (len > UINT16_MAX) return BAD_VALUE;
922 return insert((uint16_t)len, bufferpptr, bufferptrmax)
923 ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax)
924 ?: insert(name, bufferpptr, bufferptrmax)
925 ?: insert(value, bufferpptr, bufferptrmax);
926}
927
Andy Hung1efc9c62019-12-03 13:43:33 -0800928status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700929 const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
930{
931 const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
932 if (len > UINT16_MAX) return BAD_VALUE;
933 return insert((uint16_t)len, bufferpptr, bufferptrmax)
934 ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax)
935 ?: insert(name, bufferpptr, bufferptrmax)
936 ?: insert(value.first, bufferpptr, bufferptrmax)
937 ?: insert(value.second, bufferpptr, bufferptrmax);
938}
939
Andy Hung1efc9c62019-12-03 13:43:33 -0800940status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700941 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
942{
Andy Hung1efc9c62019-12-03 13:43:33 -0800943 return writeToByteString(name, (const char *)value, bufferpptr, bufferptrmax);
944}
945
946status_t BaseItem::writeToByteString(
947 const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax)
948{
Andy Hung3253f2d2019-10-21 14:50:07 -0700949 const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
950 if (len > UINT16_MAX) return BAD_VALUE;
951 return insert((uint16_t)len, bufferpptr, bufferptrmax)
952 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
953 ?: insert(name, bufferpptr, bufferptrmax)
954 ?: insert(value, bufferpptr, bufferptrmax);
955}
956
Andy Hung1efc9c62019-12-03 13:43:33 -0800957
958status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700959 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
960{
961 const size_t len = 2 + 1 + strlen(name) + 1;
962 if (len > UINT16_MAX) return BAD_VALUE;
963 return insert((uint16_t)len, bufferpptr, bufferptrmax)
964 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
965 ?: insert(name, bufferpptr, bufferptrmax);
966}
967
Andy Hung1efc9c62019-12-03 13:43:33 -0800968
Ray Essickf27e9872019-12-07 06:28:46 -0800969status_t mediametrics::Item::Prop::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700970 char **bufferpptr, char *bufferptrmax) const
971{
972 switch (mType) {
973 case kTypeInt32:
Andy Hung1efc9c62019-12-03 13:43:33 -0800974 return BaseItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700975 case kTypeInt64:
Andy Hung1efc9c62019-12-03 13:43:33 -0800976 return BaseItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700977 case kTypeDouble:
Andy Hung1efc9c62019-12-03 13:43:33 -0800978 return BaseItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700979 case kTypeRate:
Andy Hung1efc9c62019-12-03 13:43:33 -0800980 return BaseItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700981 case kTypeCString:
Andy Hung1efc9c62019-12-03 13:43:33 -0800982 return BaseItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700983 case kTypeNone:
Andy Hung1efc9c62019-12-03 13:43:33 -0800984 return BaseItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700985 default:
986 ALOGE("%s: found bad prop type: %d, name %s",
987 __func__, mType, mName); // no payload sent
988 return BAD_VALUE;
989 }
990}
991
Ray Essickf27e9872019-12-07 06:28:46 -0800992status_t mediametrics::Item::Prop::readFromByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700993 const char **bufferpptr, const char *bufferptrmax)
994{
995 uint16_t len;
996 char *name;
997 uint8_t type;
998 status_t status = extract(&len, bufferpptr, bufferptrmax)
999 ?: extract(&type, bufferpptr, bufferptrmax)
1000 ?: extract(&name, bufferpptr, bufferptrmax);
1001 if (status != NO_ERROR) return status;
1002 if (mName != nullptr) {
1003 free(mName);
1004 }
1005 mName = name;
1006 if (mType == kTypeCString) {
1007 free(u.CStringValue);
1008 u.CStringValue = nullptr;
1009 }
1010 mType = (Type)type;
1011 switch (mType) {
1012 case kTypeInt32:
1013 return extract(&u.int32Value, bufferpptr, bufferptrmax);
1014 case kTypeInt64:
1015 return extract(&u.int64Value, bufferpptr, bufferptrmax);
1016 case kTypeDouble:
1017 return extract(&u.doubleValue, bufferpptr, bufferptrmax);
1018 case kTypeRate:
1019 return extract(&u.rate.first, bufferpptr, bufferptrmax)
1020 ?: extract(&u.rate.second, bufferpptr, bufferptrmax);
1021 case kTypeCString:
1022 status = extract(&u.CStringValue, bufferpptr, bufferptrmax);
1023 if (status != NO_ERROR) mType = kTypeNone;
1024 return status;
1025 case kTypeNone:
1026 return NO_ERROR;
1027 default:
1028 mType = kTypeNone;
1029 ALOGE("%s: found bad prop type: %d, name %s",
1030 __func__, mType, mName); // no payload sent
1031 return BAD_VALUE;
1032 }
1033}
1034
Ray Essickf27e9872019-12-07 06:28:46 -08001035} // namespace android::mediametrics