blob: 14dce791a31d28a16b1618e551fb8752e2cbdbf6 [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 Essick3938dc62016-11-01 08:56:56 -070017#define LOG_TAG "MediaAnalyticsItem"
18
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>
34#include <media/IMediaAnalyticsService.h>
35#include <media/MediaAnalyticsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070036#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070037
38namespace android {
39
40#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080041#define DEBUG_API 0
42#define DEBUG_ALLOCATIONS 0
43
44// after this many failed attempts, we stop trying [from this process] and just say that
45// the service is off.
46#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070047
Ray Essickbf536ac2019-08-26 11:04:28 -070048MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
49 MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
50 return item;
51}
52
53mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
54 mediametrics_handle_t handle = (mediametrics_handle_t) item;
55 return handle;
56}
57
Ray Essick3938dc62016-11-01 08:56:56 -070058MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080059 if (DEBUG_ALLOCATIONS) {
60 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
61 }
Ray Essick3938dc62016-11-01 08:56:56 -070062 clear();
63}
64
Ray Essickb5fac8e2016-12-12 11:33:56 -080065void MediaAnalyticsItem::clear() {
66
67 // clean allocated storage from key
68 mKey.clear();
69
70 // clean attributes
71 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -070072 for (size_t i = 0 ; i < mPropCount; i++ ) {
Andy Hungaeef7882019-10-18 15:18:14 -070073 mProps[i].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -080074 }
75 // the attribute records themselves
76 if (mProps != NULL) {
77 free(mProps);
78 mProps = NULL;
79 }
80 mPropSize = 0;
81 mPropCount = 0;
82
83 return;
84}
85
86// make a deep copy of myself
87MediaAnalyticsItem *MediaAnalyticsItem::dup() {
88 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
89
90 if (dst != NULL) {
91 // key as part of constructor
92 dst->mPid = this->mPid;
93 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -070094 dst->mPkgName = this->mPkgName;
95 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -080096 dst->mTimestamp = this->mTimestamp;
Ray Essickb5fac8e2016-12-12 11:33:56 -080097
98 // properties aka attributes
99 dst->growProps(this->mPropCount);
100 for(size_t i=0;i<mPropCount;i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700101 dst->mProps[i] = this->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800102 }
103 dst->mPropCount = this->mPropCount;
104 }
105
106 return dst;
107}
108
Ray Essick3938dc62016-11-01 08:56:56 -0700109MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
110 mTimestamp = ts;
111 return *this;
112}
113
114nsecs_t MediaAnalyticsItem::getTimestamp() const {
115 return mTimestamp;
116}
117
118MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
119 mPid = pid;
120 return *this;
121}
122
123pid_t MediaAnalyticsItem::getPid() const {
124 return mPid;
125}
126
127MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
128 mUid = uid;
129 return *this;
130}
131
132uid_t MediaAnalyticsItem::getUid() const {
133 return mUid;
134}
135
Ray Essick783bd0d2018-01-11 11:10:35 -0800136MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700137 mPkgName = pkgName;
138 return *this;
139}
140
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800141MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700142 mPkgVersionCode = pkgVersionCode;
143 return *this;
144}
145
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800146int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700147 return mPkgVersionCode;
148}
149
Ray Essickb5fac8e2016-12-12 11:33:56 -0800150
151// find the proper entry in the list
Andy Hung3253f2d2019-10-21 14:50:07 -0700152size_t MediaAnalyticsItem::findPropIndex(const char *name) const
Ray Essickb5fac8e2016-12-12 11:33:56 -0800153{
154 size_t i = 0;
155 for (; i < mPropCount; i++) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700156 if (mProps[i].isNamed(name)) break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800157 }
158 return i;
159}
160
Andy Hungaeef7882019-10-18 15:18:14 -0700161MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700162 const size_t i = findPropIndex(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800163 if (i < mPropCount) {
164 return &mProps[i];
165 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700166 return nullptr;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800167}
168
Ray Essick9ce18f72018-05-07 15:54:30 -0700169// consider this "find-or-allocate".
170// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800171MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700172 const size_t i = findPropIndex(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800173 if (i < mPropCount) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700174 return &mProps[i]; // already have it, return
Ray Essickb5fac8e2016-12-12 11:33:56 -0800175 }
176
Andy Hung3253f2d2019-10-21 14:50:07 -0700177 Prop *prop = allocateProp(); // get a new prop
178 if (prop == nullptr) return nullptr;
179 prop->setName(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800180 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700181}
182
Andy Hung3253f2d2019-10-21 14:50:07 -0700183MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp() {
184 if (mPropCount == mPropSize && growProps() == false) {
185 ALOGE("%s: failed allocation for new properties", __func__);
186 return nullptr;
187 }
188 return &mProps[mPropCount++];
189}
190
Ray Essickf65f4212017-08-31 11:41:19 -0700191// used within the summarizers; return whether property existed
192bool MediaAnalyticsItem::removeProp(const char *name) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700193 const size_t i = findPropIndex(name);
Ray Essickf65f4212017-08-31 11:41:19 -0700194 if (i < mPropCount) {
Andy Hungaeef7882019-10-18 15:18:14 -0700195 mProps[i].clear();
Ray Essickf65f4212017-08-31 11:41:19 -0700196 if (i != mPropCount-1) {
197 // in the middle, bring last one down to fill gap
Andy Hungaeef7882019-10-18 15:18:14 -0700198 mProps[i].swap(mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700199 }
200 mPropCount--;
201 return true;
202 }
203 return false;
204}
205
Ray Essick3938dc62016-11-01 08:56:56 -0700206// remove indicated keys and their values
207// return value is # keys removed
Andy Hung3253f2d2019-10-21 14:50:07 -0700208size_t MediaAnalyticsItem::filter(size_t n, const char *attrs[]) {
209 size_t zapped = 0;
210 for (size_t i = 0; i < n; ++i) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800211 const char *name = attrs[i];
Andy Hung3253f2d2019-10-21 14:50:07 -0700212 size_t j = findPropIndex(name);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800213 if (j >= mPropCount) {
214 // not there
215 continue;
Andy Hung3253f2d2019-10-21 14:50:07 -0700216 } else if (j + 1 == mPropCount) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800217 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700218 zapped++;
Andy Hungaeef7882019-10-18 15:18:14 -0700219 mProps[j].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800220 mPropCount--;
221 } else {
222 // in the middle, bring last one down and shorten
223 zapped++;
Andy Hungaeef7882019-10-18 15:18:14 -0700224 mProps[j].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800225 mProps[j] = mProps[mPropCount-1];
226 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700227 }
228 }
229 return zapped;
230}
231
232// remove any keys NOT in the provided list
233// return value is # keys removed
Andy Hung3253f2d2019-10-21 14:50:07 -0700234size_t MediaAnalyticsItem::filterNot(size_t n, const char *attrs[]) {
235 std::set<std::string> check(attrs, attrs + n);
236 size_t zapped = 0;
237 for (size_t j = 0; j < mPropCount;) {
238 if (check.find(mProps[j].getName()) != check.end()) {
239 ++j;
240 continue;
241 }
242 if (j + 1 == mPropCount) {
243 // last one, shorten
244 zapped++;
245 mProps[j].clear();
246 mPropCount--;
247 break;
248 } else {
249 // in the middle, bring last one down and shorten
250 zapped++;
251 mProps[j].clear();
252 mProps[j] = mProps[mPropCount-1];
253 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700254 }
255 }
256 return zapped;
257}
258
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700259bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800260{
261 if (increment <= 0) {
262 increment = kGrowProps;
263 }
264 int nsize = mPropSize + increment;
265 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
266
267 if (ni != NULL) {
268 for (int i = mPropSize; i < nsize; i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700269 new (&ni[i]) Prop(); // placement new
Ray Essickb5fac8e2016-12-12 11:33:56 -0800270 }
271 mProps = ni;
272 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700273 return true;
274 } else {
275 ALOGW("MediaAnalyticsItem::growProps fails");
276 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800277 }
Ray Essick3938dc62016-11-01 08:56:56 -0700278}
279
280// Parcel / serialize things for binder calls
281//
282
Andy Hung3253f2d2019-10-21 14:50:07 -0700283status_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
284 int32_t version;
285 status_t status = data.readInt32(&version);
286 if (status != NO_ERROR) return status;
Ray Essickba8c4842019-01-18 11:35:33 -0800287
Andy Hung3253f2d2019-10-21 14:50:07 -0700288 switch (version) {
289 case 0:
290 return readFromParcel0(data);
291 default:
292 ALOGE("%s: unsupported parcel version: %d", __func__, version);
293 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800294 }
295}
296
Andy Hung3253f2d2019-10-21 14:50:07 -0700297status_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
298 const char *s = data.readCString();
299 mKey = s == nullptr ? "" : s;
300 int32_t pid, uid;
301 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
302 if (status != NO_ERROR) return status;
303 mPid = (pid_t)pid;
304 mUid = (uid_t)uid;
305 s = data.readCString();
306 mPkgName = s == nullptr ? "" : s;
307 int32_t count;
308 int64_t version, timestamp;
309 status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
310 if (status != NO_ERROR) return status;
311 if (count < 0) return BAD_VALUE;
312 mPkgVersionCode = version;
313 mTimestamp = timestamp;
Ray Essick3938dc62016-11-01 08:56:56 -0700314 for (int i = 0; i < count ; i++) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700315 Prop *prop = allocateProp();
316 status_t status = prop->readFromParcel(data);
317 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700318 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700319 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700320}
321
Andy Hung3253f2d2019-10-21 14:50:07 -0700322status_t MediaAnalyticsItem::writeToParcel(Parcel *data) const {
323 if (data == nullptr) return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800324
Andy Hung3253f2d2019-10-21 14:50:07 -0700325 const int32_t version = 0;
326 status_t status = data->writeInt32(version);
327 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700328
Andy Hung3253f2d2019-10-21 14:50:07 -0700329 switch (version) {
330 case 0:
331 return writeToParcel0(data);
332 default:
333 ALOGE("%s: unsupported parcel version: %d", __func__, version);
334 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800335 }
336}
337
Andy Hung3253f2d2019-10-21 14:50:07 -0700338status_t MediaAnalyticsItem::writeToParcel0(Parcel *data) const {
339 status_t status =
340 data->writeCString(mKey.c_str())
341 ?: data->writeInt32(mPid)
342 ?: data->writeInt32(mUid)
343 ?: data->writeCString(mPkgName.c_str())
344 ?: data->writeInt64(mPkgVersionCode)
345 ?: data->writeInt64(mTimestamp);
346 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700347
Andy Hung3253f2d2019-10-21 14:50:07 -0700348 data->writeInt32((int32_t)mPropCount);
349 for (size_t i = 0 ; i < mPropCount; ++i) {
350 status = mProps[i].writeToParcel(data);
351 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700352 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700353 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700354}
355
Ray Essick20147322018-11-17 09:08:39 -0800356const char *MediaAnalyticsItem::toCString() {
357 return toCString(PROTO_LAST);
358}
359
360const char * MediaAnalyticsItem::toCString(int version) {
361 std::string val = toString(version);
362 return strdup(val.c_str());
363}
364
Andy Hung17dbaf22019-10-11 14:06:31 -0700365std::string MediaAnalyticsItem::toString() const {
Ray Essick5b77bd22018-01-23 16:11:06 -0800366 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700367}
Ray Essick3938dc62016-11-01 08:56:56 -0700368
Andy Hung17dbaf22019-10-11 14:06:31 -0700369std::string MediaAnalyticsItem::toString(int version) const {
Ray Essickf65f4212017-08-31 11:41:19 -0700370
371 // v0 : released with 'o'
372 // v1 : bug fix (missing pid/finalized separator),
373 // adds apk name, apk version code
374
375 if (version <= PROTO_FIRST) {
376 // default to original v0 format, until proper parsers are in place
377 version = PROTO_V0;
378 } else if (version > PROTO_LAST) {
379 version = PROTO_LAST;
380 }
381
Ray Essick783bd0d2018-01-11 11:10:35 -0800382 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800383 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700384
Ray Essickf65f4212017-08-31 11:41:19 -0700385 if (version == PROTO_V0) {
386 result = "(";
387 } else {
388 snprintf(buffer, sizeof(buffer), "[%d:", version);
389 result.append(buffer);
390 }
391
Ray Essick3938dc62016-11-01 08:56:56 -0700392 // same order as we spill into the parcel, although not required
393 // key+session are our primary matching criteria
394 result.append(mKey.c_str());
Andy Hunga87e69c2019-10-18 10:07:40 -0700395 result.append(":0:"); // sessionID
Ray Essick3938dc62016-11-01 08:56:56 -0700396
Ray Essickf65f4212017-08-31 11:41:19 -0700397 snprintf(buffer, sizeof(buffer), "%d:", mUid);
398 result.append(buffer);
399
400 if (version >= PROTO_V1) {
401 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800402 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700403 result.append(buffer);
404 }
405
406 // in 'o' (v1) , the separator between pid and finalized was omitted
407 if (version <= PROTO_V0) {
408 snprintf(buffer, sizeof(buffer), "%d", mPid);
409 } else {
410 snprintf(buffer, sizeof(buffer), "%d:", mPid);
411 }
Ray Essick3938dc62016-11-01 08:56:56 -0700412 result.append(buffer);
413
Andy Hunga87e69c2019-10-18 10:07:40 -0700414 snprintf(buffer, sizeof(buffer), "%d:", 0 /* finalized */); // TODO: remove this.
Ray Essick3938dc62016-11-01 08:56:56 -0700415 result.append(buffer);
416 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
417 result.append(buffer);
418
419 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800420 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700421 snprintf(buffer, sizeof(buffer), "%d:", count);
422 result.append(buffer);
423 for (int i = 0 ; i < count; i++ ) {
Andy Hungaeef7882019-10-18 15:18:14 -0700424 mProps[i].toString(buffer, sizeof(buffer));
425 result.append(buffer);
Ray Essick3938dc62016-11-01 08:56:56 -0700426 }
427
Ray Essickf65f4212017-08-31 11:41:19 -0700428 if (version == PROTO_V0) {
429 result.append(")");
430 } else {
431 result.append("]");
432 }
Ray Essick3938dc62016-11-01 08:56:56 -0700433
434 return result;
435}
436
437// for the lazy, we offer methods that finds the service and
438// calls the appropriate daemon
439bool MediaAnalyticsItem::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700440 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700441 sp<IMediaAnalyticsService> svc = getInstance();
Ray Essick3938dc62016-11-01 08:56:56 -0700442 if (svc != NULL) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700443 status_t status = svc->submit(this);
444 if (status != NO_ERROR) {
445 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick2ab3c432017-10-02 09:29:49 -0700446 return false;
447 }
Ray Essick3938dc62016-11-01 08:56:56 -0700448 return true;
449 } else {
450 return false;
451 }
452}
453
Ray Essick3938dc62016-11-01 08:56:56 -0700454//static
455bool MediaAnalyticsItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700456 // completely skip logging from certain UIDs. We do this here
457 // to avoid the multi-second timeouts while we learn that
458 // sepolicy will not let us find the service.
459 // We do this only for a select set of UIDs
460 // The sepolicy protection is still in place, we just want a faster
461 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700462
Andy Hunga87e69c2019-10-18 10:07:40 -0700463 // This is checked only once in the lifetime of the process.
464 const uid_t uid = getuid();
465 switch (uid) {
466 case AID_RADIO: // telephony subsystem, RIL
467 return false;
468 }
469
470 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700471 if (enabled == -1) {
472 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
473 }
474 if (enabled == -1) {
475 enabled = MediaAnalyticsItem::EnabledProperty_default;
476 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700477 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700478}
479
Ray Essick2ab3c432017-10-02 09:29:49 -0700480// monitor health of our connection to the metrics service
481class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
482 virtual void binderDied(const wp<IBinder> &) {
483 ALOGW("Reacquire service connection on next request");
484 MediaAnalyticsItem::dropInstance();
485 }
486};
487
Andy Hunga87e69c2019-10-18 10:07:40 -0700488static sp<MediaMetricsDeathNotifier> sNotifier;
489// static
490sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
491static std::mutex sServiceMutex;
492static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700493
494// static
495void MediaAnalyticsItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700496 std::lock_guard _l(sServiceMutex);
497 sRemainingBindAttempts = SVC_TRIES;
498 sAnalyticsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700499}
500
Ray Essick3938dc62016-11-01 08:56:56 -0700501//static
502sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800503 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700504 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700505
506 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700507 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
508 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700509 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700510 std::lock_guard _l(sServiceMutex);
511 // think of remainingBindAttempts as telling us whether service == nullptr because
512 // (1) we haven't tried to initialize it yet
513 // (2) we've tried to initialize it, but failed.
514 if (sAnalyticsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700515 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700516 sp<IServiceManager> sm = defaultServiceManager();
517 if (sm != nullptr) {
518 sp<IBinder> binder = sm->getService(String16(servicename));
519 if (binder != nullptr) {
520 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
521 sNotifier = new MediaMetricsDeathNotifier();
522 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700523 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700524 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700525 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700526 } else {
527 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700528 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700529 if (sAnalyticsService == nullptr) {
530 if (sRemainingBindAttempts > 0) {
531 sRemainingBindAttempts--;
532 }
533 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
534 __func__, servicename, badness);
535 }
Ray Essick3938dc62016-11-01 08:56:56 -0700536 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700537 return sAnalyticsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700538}
539
Ray Essick3938dc62016-11-01 08:56:56 -0700540// merge the info from 'incoming' into this record.
541// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800542bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700543
544 // if I don't have key or session id, take them from incoming
545 // 'this' should never be missing both of them...
546 if (mKey.empty()) {
547 mKey = incoming->mKey;
Ray Essick3938dc62016-11-01 08:56:56 -0700548 }
549
Ray Essick3938dc62016-11-01 08:56:56 -0700550 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800551 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700552 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800553 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800554 const char *p = iprop->mName;
555 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700556
557 // should ignore a zero length name...
558 if (len == 0) {
559 continue;
560 }
561
562 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700563
Ray Essickb5fac8e2016-12-12 11:33:56 -0800564 if (oprop == NULL) {
565 // no oprop, so we insert the new one
566 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700567 if (oprop != NULL) {
Andy Hungaeef7882019-10-18 15:18:14 -0700568 *oprop = *iprop;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700569 } else {
570 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800571 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700572 } else {
Andy Hungaeef7882019-10-18 15:18:14 -0700573 *oprop = *iprop;
Ray Essick3938dc62016-11-01 08:56:56 -0700574 }
575 }
576
577 // not sure when we'd return false...
578 return true;
579}
580
Andy Hung3253f2d2019-10-21 14:50:07 -0700581namespace {
Ray Essickba8c4842019-01-18 11:35:33 -0800582
Andy Hung3253f2d2019-10-21 14:50:07 -0700583template <typename T>
584status_t insert(const T& val, char **bufferpptr, char *bufferptrmax)
585{
586 const size_t size = sizeof(val);
587 if (*bufferpptr + size > bufferptrmax) {
588 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
589 return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800590 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700591 memcpy(*bufferpptr, &val, size);
592 *bufferpptr += size;
593 return NO_ERROR;
Ray Essickba8c4842019-01-18 11:35:33 -0800594}
595
Andy Hung3253f2d2019-10-21 14:50:07 -0700596template <>
597status_t insert(const char * const& val, char **bufferpptr, char *bufferptrmax)
Andy Hungaeef7882019-10-18 15:18:14 -0700598{
Andy Hung3253f2d2019-10-21 14:50:07 -0700599 const size_t size = strlen(val) + 1;
600 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
601 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
602 return BAD_VALUE;
603 }
604 memcpy(*bufferpptr, val, size);
605 *bufferpptr += size;
606 return NO_ERROR;
607}
608
609template <>
610 __unused
611status_t insert(char * const& val, char **bufferpptr, char *bufferptrmax)
612{
613 return insert((const char *)val, bufferpptr, bufferptrmax);
614}
615
616template <typename T>
617status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax)
618{
619 const size_t size = sizeof(*val);
620 if (*bufferpptr + size > bufferptrmax) {
621 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
622 return BAD_VALUE;
623 }
624 memcpy(val, *bufferpptr, size);
625 *bufferpptr += size;
626 return NO_ERROR;
627}
628
629template <>
630status_t extract(char **val, const char **bufferpptr, const char *bufferptrmax)
631{
632 const char *ptr = *bufferpptr;
633 while (*ptr != 0) {
634 if (ptr >= bufferptrmax) {
635 ALOGE("%s: buffer exceeded", __func__);
636 }
637 ++ptr;
638 }
639 const size_t size = (ptr - *bufferpptr) + 1;
640 *val = (char *)malloc(size);
641 memcpy(*val, *bufferpptr, size);
642 *bufferpptr += size;
643 return NO_ERROR;
644}
645
646} // namespace
647
648status_t MediaAnalyticsItem::writeToByteString(char **pbuffer, size_t *plength) const
649{
650 if (pbuffer == nullptr || plength == nullptr)
651 return BAD_VALUE;
652
653 // get size
654 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
655 if (keySizeZeroTerminated > UINT16_MAX) {
656 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
657 return INVALID_OPERATION;
658 }
659 const uint16_t version = 0;
660 const uint32_t header_len =
661 sizeof(uint32_t) // overall length
662 + sizeof(header_len) // header length
663 + sizeof(version) // encoding version
664 + sizeof(uint16_t) // key length
665 + keySizeZeroTerminated // key, zero terminated
666 + sizeof(int32_t) // pid
667 + sizeof(int32_t) // uid
668 + sizeof(int64_t) // timestamp
669 ;
670
671 uint32_t len = header_len
672 + sizeof(uint32_t) // # properties
673 ;
674 for (size_t i = 0 ; i < mPropCount; ++i) {
675 const size_t size = mProps[i].getByteStringSize();
676 if (size > UINT_MAX - 1) {
677 ALOGW("%s: prop %zu has size %zu", __func__, i, size);
678 return INVALID_OPERATION;
679 }
680 len += size;
681 }
682
683 // TODO: consider package information and timestamp.
684
685 // now that we have a size... let's allocate and fill
686 char *build = (char *)calloc(1 /* nmemb */, len);
687 if (build == nullptr) return NO_MEMORY;
688
689 char *filling = build;
690 char *buildmax = build + len;
691 if (insert(len, &filling, buildmax) != NO_ERROR
692 || insert(header_len, &filling, buildmax) != NO_ERROR
693 || insert(version, &filling, buildmax) != NO_ERROR
694 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
695 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
696 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
697 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
698 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
699 || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) {
700 ALOGD("%s:could not write header", __func__);
701 free(build);
702 return INVALID_OPERATION;
703 }
704 for (size_t i = 0 ; i < mPropCount; ++i) {
705 if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) {
706 free(build);
707 ALOGD("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
708 return INVALID_OPERATION;
709 }
710 }
711
712 if (filling != buildmax) {
713 ALOGE("problems populating; wrote=%d planned=%d",
714 (int)(filling - build), len);
715 free(build);
716 return INVALID_OPERATION;
717 }
718 *pbuffer = build;
719 *plength = len;
720 return NO_ERROR;
721}
722
723status_t MediaAnalyticsItem::readFromByteString(const char *bufferptr, size_t length)
724{
725 if (bufferptr == nullptr) return BAD_VALUE;
726
727 const char *read = bufferptr;
728 const char *readend = bufferptr + length;
729
730 uint32_t len;
731 uint32_t header_len;
732 int16_t version;
733 int16_t key_len;
734 char *key = nullptr;
735 int32_t pid;
736 int32_t uid;
737 int64_t timestamp;
738 uint32_t propCount;
739 if (extract(&len, &read, readend) != NO_ERROR
740 || extract(&header_len, &read, readend) != NO_ERROR
741 || extract(&version, &read, readend) != NO_ERROR
742 || extract(&key_len, &read, readend) != NO_ERROR
743 || extract(&key, &read, readend) != NO_ERROR
744 || extract(&pid, &read, readend) != NO_ERROR
745 || extract(&uid, &read, readend) != NO_ERROR
746 || extract(&timestamp, &read, readend) != NO_ERROR
747 || len > length
748 || header_len > len) {
749 free(key);
750 ALOGD("%s: invalid header", __func__);
751 return INVALID_OPERATION;
752 }
753 mKey = key;
754 free(key);
755 const size_t pos = read - bufferptr;
756 if (pos > header_len) {
757 ALOGD("%s: invalid header pos:%zu > header_len:%u",
758 __func__, pos, header_len);
759 return INVALID_OPERATION;
760 } else if (pos < header_len) {
761 ALOGD("%s: mismatched header pos:%zu < header_len:%u, advancing",
762 __func__, pos, header_len);
763 read += (header_len - pos);
764 }
765 if (extract(&propCount, &read, readend) != NO_ERROR) {
766 ALOGD("%s: cannot read prop count", __func__);
767 return INVALID_OPERATION;
768 }
769 mPid = pid;
770 mUid = uid;
771 mTimestamp = timestamp;
772 for (size_t i = 0; i < propCount; ++i) {
773 Prop *prop = allocateProp();
774 if (prop->readFromByteString(&read, readend) != NO_ERROR) {
775 ALOGD("%s: cannot read prop %zu", __func__, i);
776 return INVALID_OPERATION;
777 }
778 }
779 return NO_ERROR;
780}
781
782status_t MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
783{
Andy Hungaeef7882019-10-18 15:18:14 -0700784 switch (mType) {
785 case kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700786 return data->writeCString(mName)
787 ?: data->writeInt32(mType)
788 ?: data->writeInt32(u.int32Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700789 case kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700790 return data->writeCString(mName)
791 ?: data->writeInt32(mType)
792 ?: data->writeInt64(u.int64Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700793 case kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700794 return data->writeCString(mName)
795 ?: data->writeInt32(mType)
796 ?: data->writeDouble(u.doubleValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700797 case kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700798 return data->writeCString(mName)
799 ?: data->writeInt32(mType)
800 ?: data->writeInt64(u.rate.first)
801 ?: data->writeInt64(u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700802 case kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700803 return data->writeCString(mName)
804 ?: data->writeInt32(mType)
805 ?: data->writeCString(u.CStringValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700806 default:
807 ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
Andy Hung3253f2d2019-10-21 14:50:07 -0700808 return BAD_VALUE;
Andy Hungaeef7882019-10-18 15:18:14 -0700809 }
810}
811
Andy Hung3253f2d2019-10-21 14:50:07 -0700812status_t MediaAnalyticsItem::Prop::readFromParcel(const Parcel& data)
813{
814 const char *key = data.readCString();
815 if (key == nullptr) return BAD_VALUE;
816 int32_t type;
817 status_t status = data.readInt32(&type);
818 if (status != NO_ERROR) return status;
819 switch (type) {
820 case kTypeInt32:
821 status = data.readInt32(&u.int32Value);
822 break;
823 case kTypeInt64:
824 status = data.readInt64(&u.int64Value);
825 break;
826 case kTypeDouble:
827 status = data.readDouble(&u.doubleValue);
828 break;
829 case kTypeCString: {
830 const char *s = data.readCString();
831 if (s == nullptr) return BAD_VALUE;
832 set(s);
833 break;
834 }
835 case kTypeRate: {
836 std::pair<int64_t, int64_t> rate;
837 status = data.readInt64(&rate.first)
838 ?: data.readInt64(&rate.second);
839 if (status == NO_ERROR) {
840 set(rate);
841 }
842 break;
843 }
844 default:
845 ALOGE("%s: reading bad item type: %d", __func__, mType);
846 return BAD_VALUE;
847 }
848 if (status == NO_ERROR) {
849 setName(key);
850 mType = (Type)type;
851 }
852 return status;
853}
854
855void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const
856{
Andy Hungaeef7882019-10-18 15:18:14 -0700857 switch (mType) {
858 case kTypeInt32:
859 snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
860 break;
861 case MediaAnalyticsItem::kTypeInt64:
862 snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value);
863 break;
864 case MediaAnalyticsItem::kTypeDouble:
865 snprintf(buffer, length, "%s=%e:", mName, u.doubleValue);
866 break;
867 case MediaAnalyticsItem::kTypeRate:
868 snprintf(buffer, length, "%s=%lld/%lld:",
Andy Hung3253f2d2019-10-21 14:50:07 -0700869 mName, (long long)u.rate.first, (long long)u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700870 break;
871 case MediaAnalyticsItem::kTypeCString:
872 // TODO sanitize string for ':' '='
873 snprintf(buffer, length, "%s=%s:", mName, u.CStringValue);
874 break;
875 default:
876 ALOGE("%s: bad item type: %d for %s", __func__, mType, mName);
877 if (length > 0) buffer[0] = 0;
878 break;
879 }
880}
881
Andy Hung3253f2d2019-10-21 14:50:07 -0700882size_t MediaAnalyticsItem::Prop::getByteStringSize() const
883{
884 const size_t header =
885 sizeof(uint16_t) // length
886 + sizeof(uint8_t) // type
887 + strlen(mName) + 1; // mName + 0 termination
888 size_t payload = 0;
889 switch (mType) {
890 case MediaAnalyticsItem::kTypeInt32:
891 payload = sizeof(u.int32Value);
892 break;
893 case MediaAnalyticsItem::kTypeInt64:
894 payload = sizeof(u.int64Value);
895 break;
896 case MediaAnalyticsItem::kTypeDouble:
897 payload = sizeof(u.doubleValue);
898 break;
899 case MediaAnalyticsItem::kTypeRate:
900 payload = sizeof(u.rate.first) + sizeof(u.rate.second);
901 break;
902 case MediaAnalyticsItem::kTypeCString:
903 payload = strlen(u.CStringValue) + 1;
904 break;
905 default:
906 ALOGE("%s: found bad prop type: %d, name %s",
907 __func__, mType, mName); // no payload computed
908 break;
909 }
910 return header + payload;
911}
Ray Essick3938dc62016-11-01 08:56:56 -0700912
Andy Hung3253f2d2019-10-21 14:50:07 -0700913// TODO: fold into a template later.
914status_t MediaAnalyticsItem::writeToByteString(
915 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
916{
917 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
918 if (len > UINT16_MAX) return BAD_VALUE;
919 return insert((uint16_t)len, bufferpptr, bufferptrmax)
920 ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax)
921 ?: insert(name, bufferpptr, bufferptrmax)
922 ?: insert(value, bufferpptr, bufferptrmax);
923}
924
925status_t MediaAnalyticsItem::writeToByteString(
926 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
927{
928 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
929 if (len > UINT16_MAX) return BAD_VALUE;
930 return insert((uint16_t)len, bufferpptr, bufferptrmax)
931 ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax)
932 ?: insert(name, bufferpptr, bufferptrmax)
933 ?: insert(value, bufferpptr, bufferptrmax);
934}
935
936status_t MediaAnalyticsItem::writeToByteString(
937 const char *name, double value, char **bufferpptr, char *bufferptrmax)
938{
939 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
940 if (len > UINT16_MAX) return BAD_VALUE;
941 return insert((uint16_t)len, bufferpptr, bufferptrmax)
942 ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax)
943 ?: insert(name, bufferpptr, bufferptrmax)
944 ?: insert(value, bufferpptr, bufferptrmax);
945}
946
947status_t MediaAnalyticsItem::writeToByteString(
948 const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
949{
950 const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
951 if (len > UINT16_MAX) return BAD_VALUE;
952 return insert((uint16_t)len, bufferpptr, bufferptrmax)
953 ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax)
954 ?: insert(name, bufferpptr, bufferptrmax)
955 ?: insert(value.first, bufferpptr, bufferptrmax)
956 ?: insert(value.second, bufferpptr, bufferptrmax);
957}
958
959status_t MediaAnalyticsItem::writeToByteString(
960 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
961{
962 const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
963 if (len > UINT16_MAX) return BAD_VALUE;
964 return insert((uint16_t)len, bufferpptr, bufferptrmax)
965 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
966 ?: insert(name, bufferpptr, bufferptrmax)
967 ?: insert(value, bufferpptr, bufferptrmax);
968}
969
970status_t MediaAnalyticsItem::writeToByteString(
971 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
972{
973 const size_t len = 2 + 1 + strlen(name) + 1;
974 if (len > UINT16_MAX) return BAD_VALUE;
975 return insert((uint16_t)len, bufferpptr, bufferptrmax)
976 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
977 ?: insert(name, bufferpptr, bufferptrmax);
978}
979
980status_t MediaAnalyticsItem::Prop::writeToByteString(
981 char **bufferpptr, char *bufferptrmax) const
982{
983 switch (mType) {
984 case kTypeInt32:
985 return MediaAnalyticsItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
986 case kTypeInt64:
987 return MediaAnalyticsItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
988 case kTypeDouble:
989 return MediaAnalyticsItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
990 case kTypeRate:
991 return MediaAnalyticsItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
992 case kTypeCString:
993 return MediaAnalyticsItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
994 case kTypeNone:
995 return MediaAnalyticsItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
996 default:
997 ALOGE("%s: found bad prop type: %d, name %s",
998 __func__, mType, mName); // no payload sent
999 return BAD_VALUE;
1000 }
1001}
1002
1003status_t MediaAnalyticsItem::Prop::readFromByteString(
1004 const char **bufferpptr, const char *bufferptrmax)
1005{
1006 uint16_t len;
1007 char *name;
1008 uint8_t type;
1009 status_t status = extract(&len, bufferpptr, bufferptrmax)
1010 ?: extract(&type, bufferpptr, bufferptrmax)
1011 ?: extract(&name, bufferpptr, bufferptrmax);
1012 if (status != NO_ERROR) return status;
1013 if (mName != nullptr) {
1014 free(mName);
1015 }
1016 mName = name;
1017 if (mType == kTypeCString) {
1018 free(u.CStringValue);
1019 u.CStringValue = nullptr;
1020 }
1021 mType = (Type)type;
1022 switch (mType) {
1023 case kTypeInt32:
1024 return extract(&u.int32Value, bufferpptr, bufferptrmax);
1025 case kTypeInt64:
1026 return extract(&u.int64Value, bufferpptr, bufferptrmax);
1027 case kTypeDouble:
1028 return extract(&u.doubleValue, bufferpptr, bufferptrmax);
1029 case kTypeRate:
1030 return extract(&u.rate.first, bufferpptr, bufferptrmax)
1031 ?: extract(&u.rate.second, bufferpptr, bufferptrmax);
1032 case kTypeCString:
1033 status = extract(&u.CStringValue, bufferpptr, bufferptrmax);
1034 if (status != NO_ERROR) mType = kTypeNone;
1035 return status;
1036 case kTypeNone:
1037 return NO_ERROR;
1038 default:
1039 mType = kTypeNone;
1040 ALOGE("%s: found bad prop type: %d, name %s",
1041 __func__, mType, mName); // no payload sent
1042 return BAD_VALUE;
1043 }
1044}
1045
1046} // namespace android