blob: 8025e49fa9a905f2f38536e5ea3fecc95e78c5c6 [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
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 Essick3938dc62016-11-01 08:56:56 -070042namespace android {
43
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 Essickbf536ac2019-08-26 11:04:28 -070052MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
53 MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
54 return item;
55}
56
57mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
58 mediametrics_handle_t handle = (mediametrics_handle_t) item;
59 return handle;
60}
61
Ray Essick3938dc62016-11-01 08:56:56 -070062MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080063 if (DEBUG_ALLOCATIONS) {
64 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
65 }
Ray Essick3938dc62016-11-01 08:56:56 -070066 clear();
67}
68
Ray Essickb5fac8e2016-12-12 11:33:56 -080069void MediaAnalyticsItem::clear() {
70
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
91MediaAnalyticsItem *MediaAnalyticsItem::dup() {
92 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
93
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 Essick3938dc62016-11-01 08:56:56 -0700113MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
114 mTimestamp = ts;
115 return *this;
116}
117
118nsecs_t MediaAnalyticsItem::getTimestamp() const {
119 return mTimestamp;
120}
121
122MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
123 mPid = pid;
124 return *this;
125}
126
127pid_t MediaAnalyticsItem::getPid() const {
128 return mPid;
129}
130
131MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
132 mUid = uid;
133 return *this;
134}
135
136uid_t MediaAnalyticsItem::getUid() const {
137 return mUid;
138}
139
Ray Essick783bd0d2018-01-11 11:10:35 -0800140MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700141 mPkgName = pkgName;
142 return *this;
143}
144
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800145MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700146 mPkgVersionCode = pkgVersionCode;
147 return *this;
148}
149
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800150int64_t MediaAnalyticsItem::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
Andy Hung3253f2d2019-10-21 14:50:07 -0700156size_t MediaAnalyticsItem::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
Andy Hungaeef7882019-10-18 15:18:14 -0700165MediaAnalyticsItem::Prop *MediaAnalyticsItem::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 Essickb5fac8e2016-12-12 11:33:56 -0800175MediaAnalyticsItem::Prop *MediaAnalyticsItem::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
Andy Hung3253f2d2019-10-21 14:50:07 -0700187MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp() {
188 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
196bool MediaAnalyticsItem::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
Andy Hung3253f2d2019-10-21 14:50:07 -0700212size_t MediaAnalyticsItem::filter(size_t n, const char *attrs[]) {
213 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
Andy Hung3253f2d2019-10-21 14:50:07 -0700238size_t MediaAnalyticsItem::filterNot(size_t n, const char *attrs[]) {
239 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 Essick9bb7e3b2017-10-23 13:01:48 -0700263bool MediaAnalyticsItem::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 {
279 ALOGW("MediaAnalyticsItem::growProps fails");
280 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
Andy Hung3253f2d2019-10-21 14:50:07 -0700287status_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
288 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
Andy Hung3253f2d2019-10-21 14:50:07 -0700301status_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
302 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
Andy Hung3253f2d2019-10-21 14:50:07 -0700326status_t MediaAnalyticsItem::writeToParcel(Parcel *data) const {
327 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
Andy Hung3253f2d2019-10-21 14:50:07 -0700342status_t MediaAnalyticsItem::writeToParcel0(Parcel *data) const {
343 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 Essick20147322018-11-17 09:08:39 -0800360const char *MediaAnalyticsItem::toCString() {
361 return toCString(PROTO_LAST);
362}
363
364const char * MediaAnalyticsItem::toCString(int version) {
365 std::string val = toString(version);
366 return strdup(val.c_str());
367}
368
Andy Hung17dbaf22019-10-11 14:06:31 -0700369std::string MediaAnalyticsItem::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
Andy Hung17dbaf22019-10-11 14:06:31 -0700373std::string MediaAnalyticsItem::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
391bool MediaAnalyticsItem::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700392 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700393 sp<IMediaAnalyticsService> 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
Andy Hung1efc9c62019-12-03 13:43:33 -0800406namespace mediametrics {
Ray Essick3938dc62016-11-01 08:56:56 -0700407//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800408bool BaseItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700409 // completely skip logging from certain UIDs. We do this here
410 // to avoid the multi-second timeouts while we learn that
411 // sepolicy will not let us find the service.
412 // We do this only for a select set of UIDs
413 // The sepolicy protection is still in place, we just want a faster
414 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700415
Andy Hunga87e69c2019-10-18 10:07:40 -0700416 // This is checked only once in the lifetime of the process.
417 const uid_t uid = getuid();
418 switch (uid) {
419 case AID_RADIO: // telephony subsystem, RIL
420 return false;
421 }
422
423 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700424 if (enabled == -1) {
425 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
426 }
427 if (enabled == -1) {
428 enabled = MediaAnalyticsItem::EnabledProperty_default;
429 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700430 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700431}
432
Ray Essick2ab3c432017-10-02 09:29:49 -0700433// monitor health of our connection to the metrics service
434class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
435 virtual void binderDied(const wp<IBinder> &) {
436 ALOGW("Reacquire service connection on next request");
Andy Hung1efc9c62019-12-03 13:43:33 -0800437 BaseItem::dropInstance();
Ray Essick2ab3c432017-10-02 09:29:49 -0700438 }
439};
440
Andy Hunga87e69c2019-10-18 10:07:40 -0700441static sp<MediaMetricsDeathNotifier> sNotifier;
442// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800443sp<IMediaAnalyticsService> BaseItem::sAnalyticsService;
Andy Hunga87e69c2019-10-18 10:07:40 -0700444static std::mutex sServiceMutex;
445static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700446
447// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800448void BaseItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700449 std::lock_guard _l(sServiceMutex);
450 sRemainingBindAttempts = SVC_TRIES;
451 sAnalyticsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700452}
453
Andy Hung1efc9c62019-12-03 13:43:33 -0800454// static
455bool BaseItem::submitBuffer(const char *buffer, size_t size) {
456/*
457 MediaAnalyticsItem item;
458 status_t status = item.readFromByteString(buffer, size);
459 ALOGD("%s: status:%d, size:%zu, item:%s", __func__, status, size, item.toString().c_str());
460 return item.selfrecord();
461 */
462
463 ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
464 sp<IMediaAnalyticsService> svc = getInstance();
465 if (svc != nullptr) {
466 const status_t status = svc->submitBuffer(buffer, size);
467 if (status != NO_ERROR) {
468 ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
469 return false;
470 }
471 return true;
472 }
473 return false;
474}
475
Ray Essick3938dc62016-11-01 08:56:56 -0700476//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800477sp<IMediaAnalyticsService> BaseItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800478 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700479 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700480
481 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700482 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
483 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700484 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700485 std::lock_guard _l(sServiceMutex);
486 // think of remainingBindAttempts as telling us whether service == nullptr because
487 // (1) we haven't tried to initialize it yet
488 // (2) we've tried to initialize it, but failed.
489 if (sAnalyticsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700490 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700491 sp<IServiceManager> sm = defaultServiceManager();
492 if (sm != nullptr) {
493 sp<IBinder> binder = sm->getService(String16(servicename));
494 if (binder != nullptr) {
495 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
496 sNotifier = new MediaMetricsDeathNotifier();
497 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700498 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700499 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700500 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700501 } else {
502 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700503 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700504 if (sAnalyticsService == nullptr) {
505 if (sRemainingBindAttempts > 0) {
506 sRemainingBindAttempts--;
507 }
508 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
509 __func__, servicename, badness);
510 }
Ray Essick3938dc62016-11-01 08:56:56 -0700511 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700512 return sAnalyticsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700513}
514
Andy Hung1efc9c62019-12-03 13:43:33 -0800515} // namespace mediametrics
516
Ray Essick3938dc62016-11-01 08:56:56 -0700517// merge the info from 'incoming' into this record.
518// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800519bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700520
521 // if I don't have key or session id, take them from incoming
522 // 'this' should never be missing both of them...
523 if (mKey.empty()) {
524 mKey = incoming->mKey;
Ray Essick3938dc62016-11-01 08:56:56 -0700525 }
526
Ray Essick3938dc62016-11-01 08:56:56 -0700527 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800528 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700529 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800530 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800531 const char *p = iprop->mName;
532 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700533
534 // should ignore a zero length name...
535 if (len == 0) {
536 continue;
537 }
538
539 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700540
Ray Essickb5fac8e2016-12-12 11:33:56 -0800541 if (oprop == NULL) {
542 // no oprop, so we insert the new one
543 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700544 if (oprop != NULL) {
Andy Hungaeef7882019-10-18 15:18:14 -0700545 *oprop = *iprop;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700546 } else {
547 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800548 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700549 } else {
Andy Hungaeef7882019-10-18 15:18:14 -0700550 *oprop = *iprop;
Ray Essick3938dc62016-11-01 08:56:56 -0700551 }
552 }
553
554 // not sure when we'd return false...
555 return true;
556}
557
Andy Hung3253f2d2019-10-21 14:50:07 -0700558namespace {
Ray Essickba8c4842019-01-18 11:35:33 -0800559
Andy Hung3253f2d2019-10-21 14:50:07 -0700560template <typename T>
561status_t insert(const T& val, char **bufferpptr, char *bufferptrmax)
562{
563 const size_t size = sizeof(val);
564 if (*bufferpptr + size > bufferptrmax) {
565 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
566 return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800567 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700568 memcpy(*bufferpptr, &val, size);
569 *bufferpptr += size;
570 return NO_ERROR;
Ray Essickba8c4842019-01-18 11:35:33 -0800571}
572
Andy Hung3253f2d2019-10-21 14:50:07 -0700573template <>
574status_t insert(const char * const& val, char **bufferpptr, char *bufferptrmax)
Andy Hungaeef7882019-10-18 15:18:14 -0700575{
Andy Hung3253f2d2019-10-21 14:50:07 -0700576 const size_t size = strlen(val) + 1;
577 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
578 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
579 return BAD_VALUE;
580 }
581 memcpy(*bufferpptr, val, size);
582 *bufferpptr += size;
583 return NO_ERROR;
584}
585
586template <>
587 __unused
588status_t insert(char * const& val, char **bufferpptr, char *bufferptrmax)
589{
590 return insert((const char *)val, bufferpptr, bufferptrmax);
591}
592
593template <typename T>
594status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax)
595{
596 const size_t size = sizeof(*val);
597 if (*bufferpptr + size > bufferptrmax) {
598 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
599 return BAD_VALUE;
600 }
601 memcpy(val, *bufferpptr, size);
602 *bufferpptr += size;
603 return NO_ERROR;
604}
605
606template <>
607status_t extract(char **val, const char **bufferpptr, const char *bufferptrmax)
608{
609 const char *ptr = *bufferpptr;
610 while (*ptr != 0) {
611 if (ptr >= bufferptrmax) {
612 ALOGE("%s: buffer exceeded", __func__);
Andy Hung1efc9c62019-12-03 13:43:33 -0800613 return BAD_VALUE;
Andy Hung3253f2d2019-10-21 14:50:07 -0700614 }
615 ++ptr;
616 }
617 const size_t size = (ptr - *bufferpptr) + 1;
618 *val = (char *)malloc(size);
619 memcpy(*val, *bufferpptr, size);
620 *bufferpptr += size;
621 return NO_ERROR;
622}
623
624} // namespace
625
626status_t MediaAnalyticsItem::writeToByteString(char **pbuffer, size_t *plength) const
627{
628 if (pbuffer == nullptr || plength == nullptr)
629 return BAD_VALUE;
630
631 // get size
632 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
633 if (keySizeZeroTerminated > UINT16_MAX) {
634 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
635 return INVALID_OPERATION;
636 }
637 const uint16_t version = 0;
Andy Hung1efc9c62019-12-03 13:43:33 -0800638 const uint32_t header_size =
639 sizeof(uint32_t) // total size
640 + sizeof(header_size) // header size
641 + sizeof(version) // encoding version
642 + sizeof(uint16_t) // key size
Andy Hung3253f2d2019-10-21 14:50:07 -0700643 + keySizeZeroTerminated // key, zero terminated
Andy Hung1efc9c62019-12-03 13:43:33 -0800644 + sizeof(int32_t) // pid
645 + sizeof(int32_t) // uid
646 + sizeof(int64_t) // timestamp
Andy Hung3253f2d2019-10-21 14:50:07 -0700647 ;
648
Andy Hung1efc9c62019-12-03 13:43:33 -0800649 uint32_t size = header_size
Andy Hung3253f2d2019-10-21 14:50:07 -0700650 + sizeof(uint32_t) // # properties
651 ;
652 for (size_t i = 0 ; i < mPropCount; ++i) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800653 const size_t propSize = mProps[i].getByteStringSize();
654 if (propSize > UINT16_MAX) {
655 ALOGW("%s: prop %zu size %zu too large", __func__, i, propSize);
Andy Hung3253f2d2019-10-21 14:50:07 -0700656 return INVALID_OPERATION;
657 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800658 if (__builtin_add_overflow(size, propSize, &size)) {
659 ALOGW("%s: item size overflow at property %zu", __func__, i);
660 return INVALID_OPERATION;
661 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700662 }
663
Andy Hung1efc9c62019-12-03 13:43:33 -0800664 // since we fill every byte in the buffer (there is no padding),
665 // malloc is used here instead of calloc.
666 char * const build = (char *)malloc(size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700667 if (build == nullptr) return NO_MEMORY;
668
669 char *filling = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800670 char *buildmax = build + size;
671 if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
672 || insert(header_size, &filling, buildmax) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700673 || insert(version, &filling, buildmax) != NO_ERROR
674 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
675 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
676 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
677 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
678 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
679 || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800680 ALOGE("%s:could not write header", __func__); // shouldn't happen
Andy Hung3253f2d2019-10-21 14:50:07 -0700681 free(build);
682 return INVALID_OPERATION;
683 }
684 for (size_t i = 0 ; i < mPropCount; ++i) {
685 if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) {
686 free(build);
Andy Hung1efc9c62019-12-03 13:43:33 -0800687 // shouldn't happen
688 ALOGE("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
Andy Hung3253f2d2019-10-21 14:50:07 -0700689 return INVALID_OPERATION;
690 }
691 }
692
693 if (filling != buildmax) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800694 ALOGE("%s: problems populating; wrote=%d planned=%d",
695 __func__, (int)(filling - build), (int)size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700696 free(build);
697 return INVALID_OPERATION;
698 }
699 *pbuffer = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800700 *plength = size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700701 return NO_ERROR;
702}
703
704status_t MediaAnalyticsItem::readFromByteString(const char *bufferptr, size_t length)
705{
706 if (bufferptr == nullptr) return BAD_VALUE;
707
708 const char *read = bufferptr;
709 const char *readend = bufferptr + length;
710
Andy Hung1efc9c62019-12-03 13:43:33 -0800711 uint32_t size;
712 uint32_t header_size;
713 uint16_t version;
714 uint16_t key_size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700715 char *key = nullptr;
716 int32_t pid;
717 int32_t uid;
718 int64_t timestamp;
719 uint32_t propCount;
Andy Hung1efc9c62019-12-03 13:43:33 -0800720 if (extract(&size, &read, readend) != NO_ERROR
721 || extract(&header_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700722 || extract(&version, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800723 || extract(&key_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700724 || extract(&key, &read, readend) != NO_ERROR
725 || extract(&pid, &read, readend) != NO_ERROR
726 || extract(&uid, &read, readend) != NO_ERROR
727 || extract(&timestamp, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800728 || size > length
729 || strlen(key) + 1 != key_size
730 || header_size > size) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700731 free(key);
Andy Hung1efc9c62019-12-03 13:43:33 -0800732 ALOGW("%s: invalid header", __func__);
Andy Hung3253f2d2019-10-21 14:50:07 -0700733 return INVALID_OPERATION;
734 }
735 mKey = key;
736 free(key);
737 const size_t pos = read - bufferptr;
Andy Hung1efc9c62019-12-03 13:43:33 -0800738 if (pos > header_size) {
739 ALOGW("%s: invalid header pos:%zu > header_size:%u",
740 __func__, pos, header_size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700741 return INVALID_OPERATION;
Andy Hung1efc9c62019-12-03 13:43:33 -0800742 } else if (pos < header_size) {
743 ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
744 __func__, pos, header_size);
745 read += (header_size - pos);
Andy Hung3253f2d2019-10-21 14:50:07 -0700746 }
747 if (extract(&propCount, &read, readend) != NO_ERROR) {
748 ALOGD("%s: cannot read prop count", __func__);
749 return INVALID_OPERATION;
750 }
751 mPid = pid;
752 mUid = uid;
753 mTimestamp = timestamp;
754 for (size_t i = 0; i < propCount; ++i) {
755 Prop *prop = allocateProp();
756 if (prop->readFromByteString(&read, readend) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800757 ALOGW("%s: cannot read prop %zu", __func__, i);
Andy Hung3253f2d2019-10-21 14:50:07 -0700758 return INVALID_OPERATION;
759 }
760 }
761 return NO_ERROR;
762}
763
764status_t MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
765{
Andy Hungaeef7882019-10-18 15:18:14 -0700766 switch (mType) {
767 case kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700768 return data->writeCString(mName)
769 ?: data->writeInt32(mType)
770 ?: data->writeInt32(u.int32Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700771 case kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700772 return data->writeCString(mName)
773 ?: data->writeInt32(mType)
774 ?: data->writeInt64(u.int64Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700775 case kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700776 return data->writeCString(mName)
777 ?: data->writeInt32(mType)
778 ?: data->writeDouble(u.doubleValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700779 case kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700780 return data->writeCString(mName)
781 ?: data->writeInt32(mType)
782 ?: data->writeInt64(u.rate.first)
783 ?: data->writeInt64(u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700784 case kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700785 return data->writeCString(mName)
786 ?: data->writeInt32(mType)
787 ?: data->writeCString(u.CStringValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700788 default:
789 ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
Andy Hung3253f2d2019-10-21 14:50:07 -0700790 return BAD_VALUE;
Andy Hungaeef7882019-10-18 15:18:14 -0700791 }
792}
793
Andy Hung3253f2d2019-10-21 14:50:07 -0700794status_t MediaAnalyticsItem::Prop::readFromParcel(const Parcel& data)
795{
796 const char *key = data.readCString();
797 if (key == nullptr) return BAD_VALUE;
798 int32_t type;
799 status_t status = data.readInt32(&type);
800 if (status != NO_ERROR) return status;
801 switch (type) {
802 case kTypeInt32:
803 status = data.readInt32(&u.int32Value);
804 break;
805 case kTypeInt64:
806 status = data.readInt64(&u.int64Value);
807 break;
808 case kTypeDouble:
809 status = data.readDouble(&u.doubleValue);
810 break;
811 case kTypeCString: {
812 const char *s = data.readCString();
813 if (s == nullptr) return BAD_VALUE;
814 set(s);
815 break;
816 }
817 case kTypeRate: {
818 std::pair<int64_t, int64_t> rate;
819 status = data.readInt64(&rate.first)
820 ?: data.readInt64(&rate.second);
821 if (status == NO_ERROR) {
822 set(rate);
823 }
824 break;
825 }
826 default:
827 ALOGE("%s: reading bad item type: %d", __func__, mType);
828 return BAD_VALUE;
829 }
830 if (status == NO_ERROR) {
831 setName(key);
832 mType = (Type)type;
833 }
834 return status;
835}
836
837void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const
838{
Andy Hungaeef7882019-10-18 15:18:14 -0700839 switch (mType) {
840 case kTypeInt32:
841 snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
842 break;
843 case MediaAnalyticsItem::kTypeInt64:
844 snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value);
845 break;
846 case MediaAnalyticsItem::kTypeDouble:
847 snprintf(buffer, length, "%s=%e:", mName, u.doubleValue);
848 break;
849 case MediaAnalyticsItem::kTypeRate:
850 snprintf(buffer, length, "%s=%lld/%lld:",
Andy Hung3253f2d2019-10-21 14:50:07 -0700851 mName, (long long)u.rate.first, (long long)u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700852 break;
853 case MediaAnalyticsItem::kTypeCString:
854 // TODO sanitize string for ':' '='
855 snprintf(buffer, length, "%s=%s:", mName, u.CStringValue);
856 break;
857 default:
858 ALOGE("%s: bad item type: %d for %s", __func__, mType, mName);
859 if (length > 0) buffer[0] = 0;
860 break;
861 }
862}
863
Andy Hung3253f2d2019-10-21 14:50:07 -0700864size_t MediaAnalyticsItem::Prop::getByteStringSize() const
865{
866 const size_t header =
867 sizeof(uint16_t) // length
868 + sizeof(uint8_t) // type
869 + strlen(mName) + 1; // mName + 0 termination
870 size_t payload = 0;
871 switch (mType) {
872 case MediaAnalyticsItem::kTypeInt32:
873 payload = sizeof(u.int32Value);
874 break;
875 case MediaAnalyticsItem::kTypeInt64:
876 payload = sizeof(u.int64Value);
877 break;
878 case MediaAnalyticsItem::kTypeDouble:
879 payload = sizeof(u.doubleValue);
880 break;
881 case MediaAnalyticsItem::kTypeRate:
882 payload = sizeof(u.rate.first) + sizeof(u.rate.second);
883 break;
884 case MediaAnalyticsItem::kTypeCString:
885 payload = strlen(u.CStringValue) + 1;
886 break;
887 default:
888 ALOGE("%s: found bad prop type: %d, name %s",
889 __func__, mType, mName); // no payload computed
890 break;
891 }
892 return header + payload;
893}
Ray Essick3938dc62016-11-01 08:56:56 -0700894
Andy Hung1efc9c62019-12-03 13:43:33 -0800895namespace mediametrics {
896
Andy Hung3253f2d2019-10-21 14:50:07 -0700897// TODO: fold into a template later.
Andy Hung1efc9c62019-12-03 13:43:33 -0800898status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700899 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
900{
901 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
902 if (len > UINT16_MAX) return BAD_VALUE;
903 return insert((uint16_t)len, bufferpptr, bufferptrmax)
904 ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax)
905 ?: insert(name, bufferpptr, bufferptrmax)
906 ?: insert(value, bufferpptr, bufferptrmax);
907}
908
Andy Hung1efc9c62019-12-03 13:43:33 -0800909status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700910 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
911{
912 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
913 if (len > UINT16_MAX) return BAD_VALUE;
914 return insert((uint16_t)len, bufferpptr, bufferptrmax)
915 ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax)
916 ?: insert(name, bufferpptr, bufferptrmax)
917 ?: insert(value, bufferpptr, bufferptrmax);
918}
919
Andy Hung1efc9c62019-12-03 13:43:33 -0800920status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700921 const char *name, double value, char **bufferpptr, char *bufferptrmax)
922{
923 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
924 if (len > UINT16_MAX) return BAD_VALUE;
925 return insert((uint16_t)len, bufferpptr, bufferptrmax)
926 ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax)
927 ?: insert(name, bufferpptr, bufferptrmax)
928 ?: insert(value, bufferpptr, bufferptrmax);
929}
930
Andy Hung1efc9c62019-12-03 13:43:33 -0800931status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700932 const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
933{
934 const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
935 if (len > UINT16_MAX) return BAD_VALUE;
936 return insert((uint16_t)len, bufferpptr, bufferptrmax)
937 ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax)
938 ?: insert(name, bufferpptr, bufferptrmax)
939 ?: insert(value.first, bufferpptr, bufferptrmax)
940 ?: insert(value.second, bufferpptr, bufferptrmax);
941}
942
Andy Hung1efc9c62019-12-03 13:43:33 -0800943status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700944 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
945{
Andy Hung1efc9c62019-12-03 13:43:33 -0800946 return writeToByteString(name, (const char *)value, bufferpptr, bufferptrmax);
947}
948
949status_t BaseItem::writeToByteString(
950 const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax)
951{
Andy Hung3253f2d2019-10-21 14:50:07 -0700952 const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
953 if (len > UINT16_MAX) return BAD_VALUE;
954 return insert((uint16_t)len, bufferpptr, bufferptrmax)
955 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
956 ?: insert(name, bufferpptr, bufferptrmax)
957 ?: insert(value, bufferpptr, bufferptrmax);
958}
959
Andy Hung1efc9c62019-12-03 13:43:33 -0800960
961status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700962 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
963{
964 const size_t len = 2 + 1 + strlen(name) + 1;
965 if (len > UINT16_MAX) return BAD_VALUE;
966 return insert((uint16_t)len, bufferpptr, bufferptrmax)
967 ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
968 ?: insert(name, bufferpptr, bufferptrmax);
969}
970
Andy Hung1efc9c62019-12-03 13:43:33 -0800971} // namespace mediametrics
972
Andy Hung3253f2d2019-10-21 14:50:07 -0700973status_t MediaAnalyticsItem::Prop::writeToByteString(
974 char **bufferpptr, char *bufferptrmax) const
975{
976 switch (mType) {
977 case kTypeInt32:
Andy Hung1efc9c62019-12-03 13:43:33 -0800978 return BaseItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700979 case kTypeInt64:
Andy Hung1efc9c62019-12-03 13:43:33 -0800980 return BaseItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700981 case kTypeDouble:
Andy Hung1efc9c62019-12-03 13:43:33 -0800982 return BaseItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700983 case kTypeRate:
Andy Hung1efc9c62019-12-03 13:43:33 -0800984 return BaseItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700985 case kTypeCString:
Andy Hung1efc9c62019-12-03 13:43:33 -0800986 return BaseItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700987 case kTypeNone:
Andy Hung1efc9c62019-12-03 13:43:33 -0800988 return BaseItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700989 default:
990 ALOGE("%s: found bad prop type: %d, name %s",
991 __func__, mType, mName); // no payload sent
992 return BAD_VALUE;
993 }
994}
995
996status_t MediaAnalyticsItem::Prop::readFromByteString(
997 const char **bufferpptr, const char *bufferptrmax)
998{
999 uint16_t len;
1000 char *name;
1001 uint8_t type;
1002 status_t status = extract(&len, bufferpptr, bufferptrmax)
1003 ?: extract(&type, bufferpptr, bufferptrmax)
1004 ?: extract(&name, bufferpptr, bufferptrmax);
1005 if (status != NO_ERROR) return status;
1006 if (mName != nullptr) {
1007 free(mName);
1008 }
1009 mName = name;
1010 if (mType == kTypeCString) {
1011 free(u.CStringValue);
1012 u.CStringValue = nullptr;
1013 }
1014 mType = (Type)type;
1015 switch (mType) {
1016 case kTypeInt32:
1017 return extract(&u.int32Value, bufferpptr, bufferptrmax);
1018 case kTypeInt64:
1019 return extract(&u.int64Value, bufferpptr, bufferptrmax);
1020 case kTypeDouble:
1021 return extract(&u.doubleValue, bufferpptr, bufferptrmax);
1022 case kTypeRate:
1023 return extract(&u.rate.first, bufferpptr, bufferptrmax)
1024 ?: extract(&u.rate.second, bufferpptr, bufferptrmax);
1025 case kTypeCString:
1026 status = extract(&u.CStringValue, bufferpptr, bufferptrmax);
1027 if (status != NO_ERROR) mType = kTypeNone;
1028 return status;
1029 case kTypeNone:
1030 return NO_ERROR;
1031 default:
1032 mType = kTypeNone;
1033 ALOGE("%s: found bad prop type: %d, name %s",
1034 __func__, mType, mName); // no payload sent
1035 return BAD_VALUE;
1036 }
1037}
1038
1039} // namespace android