blob: 20b10db33fef727a1e1deaf8a64265c1c567e695 [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
17#undef LOG_TAG
18#define LOG_TAG "MediaAnalyticsItem"
19
Ray Essick3938dc62016-11-01 08:56:56 -070020#include <inttypes.h>
Ray Essickb5fac8e2016-12-12 11:33:56 -080021#include <stdlib.h>
22#include <string.h>
23#include <sys/types.h>
Ray Essick3938dc62016-11-01 08:56:56 -070024
Andy Hunga87e69c2019-10-18 10:07:40 -070025#include <mutex>
26
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
48// the few universal keys we have
49const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
50const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
51
Ray Essickd38e1742017-01-23 15:17:06 -080052const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
53const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
Ray Essickd6a6c672017-01-25 14:28:51 -080054const int MediaAnalyticsItem::EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -070055
Ray Essickba8c4842019-01-18 11:35:33 -080056// So caller doesn't need to know size of allocated space
57MediaAnalyticsItem *MediaAnalyticsItem::create()
58{
59 return MediaAnalyticsItem::create(kKeyNone);
60}
61
62MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
63{
64 MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
65 return item;
66}
Ray Essick3938dc62016-11-01 08:56:56 -070067
Ray Essickbf536ac2019-08-26 11:04:28 -070068MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
69 MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
70 return item;
71}
72
73mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
74 mediametrics_handle_t handle = (mediametrics_handle_t) item;
75 return handle;
76}
77
Ray Essick3938dc62016-11-01 08:56:56 -070078// access functions for the class
79MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080080 : mPid(-1),
81 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070082 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070083 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080084 mPropCount(0), mPropSize(0), mProps(NULL)
85{
Ray Essick3938dc62016-11-01 08:56:56 -070086 mKey = MediaAnalyticsItem::kKeyNone;
87}
88
89MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080090 : mPid(-1),
91 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070092 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070093 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080094 mPropCount(0), mPropSize(0), mProps(NULL)
95{
96 if (DEBUG_ALLOCATIONS) {
97 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
98 }
Ray Essick3938dc62016-11-01 08:56:56 -070099 mKey = key;
100}
101
102MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800103 if (DEBUG_ALLOCATIONS) {
104 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
105 }
Ray Essick3938dc62016-11-01 08:56:56 -0700106 clear();
107}
108
Ray Essickb5fac8e2016-12-12 11:33:56 -0800109void MediaAnalyticsItem::clear() {
110
111 // clean allocated storage from key
112 mKey.clear();
113
114 // clean attributes
115 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700116 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800117 clearProp(&mProps[i]);
118 }
119 // the attribute records themselves
120 if (mProps != NULL) {
121 free(mProps);
122 mProps = NULL;
123 }
124 mPropSize = 0;
125 mPropCount = 0;
126
127 return;
128}
129
130// make a deep copy of myself
131MediaAnalyticsItem *MediaAnalyticsItem::dup() {
132 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
133
134 if (dst != NULL) {
135 // key as part of constructor
136 dst->mPid = this->mPid;
137 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700138 dst->mPkgName = this->mPkgName;
139 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800140 dst->mTimestamp = this->mTimestamp;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800141
142 // properties aka attributes
143 dst->growProps(this->mPropCount);
144 for(size_t i=0;i<mPropCount;i++) {
145 copyProp(&dst->mProps[i], &this->mProps[i]);
146 }
147 dst->mPropCount = this->mPropCount;
148 }
149
150 return dst;
151}
152
Ray Essick3938dc62016-11-01 08:56:56 -0700153MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
154 mTimestamp = ts;
155 return *this;
156}
157
158nsecs_t MediaAnalyticsItem::getTimestamp() const {
159 return mTimestamp;
160}
161
162MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
163 mPid = pid;
164 return *this;
165}
166
167pid_t MediaAnalyticsItem::getPid() const {
168 return mPid;
169}
170
171MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
172 mUid = uid;
173 return *this;
174}
175
176uid_t MediaAnalyticsItem::getUid() const {
177 return mUid;
178}
179
Ray Essick783bd0d2018-01-11 11:10:35 -0800180MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700181 mPkgName = pkgName;
182 return *this;
183}
184
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800185MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700186 mPkgVersionCode = pkgVersionCode;
187 return *this;
188}
189
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800190int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700191 return mPkgVersionCode;
192}
193
Ray Essickb5fac8e2016-12-12 11:33:56 -0800194// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700195MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700196 mKey = key;
197 return *this;
198}
199
Ray Essickb5fac8e2016-12-12 11:33:56 -0800200// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700201int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800202 return mPropCount;
203}
204
205// find the proper entry in the list
206size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
207{
208 size_t i = 0;
209 for (; i < mPropCount; i++) {
210 Prop *prop = &mProps[i];
211 if (prop->mNameLen != len) {
212 continue;
213 }
214 if (memcmp(name, prop->mName, len) == 0) {
215 break;
216 }
217 }
218 return i;
219}
220
221MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
222 size_t len = strlen(name);
223 size_t i = findPropIndex(name, len);
224 if (i < mPropCount) {
225 return &mProps[i];
226 }
227 return NULL;
228}
229
230void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700231 free((void *)mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800232 mName = (const char *) malloc(len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700233 LOG_ALWAYS_FATAL_IF(mName == NULL,
234 "failed malloc() for property '%s' (len %zu)",
235 name, len);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800236 memcpy ((void *)mName, name, len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700237 mNameLen = len;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800238}
239
Ray Essick9ce18f72018-05-07 15:54:30 -0700240// consider this "find-or-allocate".
241// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800242MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
243 size_t len = strlen(name);
244 size_t i = findPropIndex(name, len);
245 Prop *prop;
246
247 if (i < mPropCount) {
248 prop = &mProps[i];
249 } else {
250 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700251 if (growProps() == false) {
252 ALOGE("failed allocation for new props");
253 return NULL;
254 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800255 }
256 i = mPropCount++;
257 prop = &mProps[i];
258 prop->setName(name, len);
259 }
260
261 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700262}
263
Ray Essickf65f4212017-08-31 11:41:19 -0700264// used within the summarizers; return whether property existed
265bool MediaAnalyticsItem::removeProp(const char *name) {
266 size_t len = strlen(name);
267 size_t i = findPropIndex(name, len);
268 if (i < mPropCount) {
269 Prop *prop = &mProps[i];
270 clearProp(prop);
271 if (i != mPropCount-1) {
272 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700273 copyProp(prop, &mProps[mPropCount-1]);
274 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700275 }
276 mPropCount--;
277 return true;
278 }
279 return false;
280}
281
Ray Essick3938dc62016-11-01 08:56:56 -0700282// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800283void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
284 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700285 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700286 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700287 prop->mType = kTypeInt32;
288 prop->u.int32Value = value;
289 }
Ray Essick3938dc62016-11-01 08:56:56 -0700290}
291
Ray Essickb5fac8e2016-12-12 11:33:56 -0800292void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
293 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700294 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700295 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700296 prop->mType = kTypeInt64;
297 prop->u.int64Value = value;
298 }
Ray Essick3938dc62016-11-01 08:56:56 -0700299}
300
Ray Essickb5fac8e2016-12-12 11:33:56 -0800301void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
302 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700303 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700304 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700305 prop->mType = kTypeDouble;
306 prop->u.doubleValue = value;
307 }
Ray Essick3938dc62016-11-01 08:56:56 -0700308}
309
Ray Essickb5fac8e2016-12-12 11:33:56 -0800310void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
311
312 Prop *prop = allocateProp(name);
313 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700314 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700315 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700316 prop->mType = kTypeCString;
317 prop->u.CStringValue = strdup(value);
318 }
Ray Essick3938dc62016-11-01 08:56:56 -0700319}
320
Ray Essickb5fac8e2016-12-12 11:33:56 -0800321void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
322 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700323 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700324 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700325 prop->mType = kTypeRate;
326 prop->u.rate.count = count;
327 prop->u.rate.duration = duration;
328 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800329}
330
331
Ray Essick3938dc62016-11-01 08:56:56 -0700332// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800333void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
334 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700335 if (prop == NULL) {
336 return;
337 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800338 switch (prop->mType) {
339 case kTypeInt32:
340 prop->u.int32Value += value;
341 break;
342 default:
343 clearPropValue(prop);
344 prop->mType = kTypeInt32;
345 prop->u.int32Value = value;
346 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700347 }
Ray Essick3938dc62016-11-01 08:56:56 -0700348}
349
Ray Essickb5fac8e2016-12-12 11:33:56 -0800350void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
351 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700352 if (prop == NULL) {
353 return;
354 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800355 switch (prop->mType) {
356 case kTypeInt64:
357 prop->u.int64Value += value;
358 break;
359 default:
360 clearPropValue(prop);
361 prop->mType = kTypeInt64;
362 prop->u.int64Value = value;
363 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700364 }
Ray Essick3938dc62016-11-01 08:56:56 -0700365}
366
Ray Essickb5fac8e2016-12-12 11:33:56 -0800367void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
368 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700369 if (prop == NULL) {
370 return;
371 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800372 switch (prop->mType) {
373 case kTypeRate:
374 prop->u.rate.count += count;
375 prop->u.rate.duration += duration;
376 break;
377 default:
378 clearPropValue(prop);
379 prop->mType = kTypeRate;
380 prop->u.rate.count = count;
381 prop->u.rate.duration = duration;
382 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700383 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800384}
385
386void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
387 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700388 if (prop == NULL) {
389 return;
390 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800391 switch (prop->mType) {
392 case kTypeDouble:
393 prop->u.doubleValue += value;
394 break;
395 default:
396 clearPropValue(prop);
397 prop->mType = kTypeDouble;
398 prop->u.doubleValue = value;
399 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700400 }
Ray Essick3938dc62016-11-01 08:56:56 -0700401}
402
403// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800404bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
405 Prop *prop = findProp(name);
406 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700407 return false;
408 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800409 if (value != NULL) {
410 *value = prop->u.int32Value;
411 }
Ray Essick3938dc62016-11-01 08:56:56 -0700412 return true;
413}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800414
415bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
416 Prop *prop = findProp(name);
417 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700418 return false;
419 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800420 if (value != NULL) {
421 *value = prop->u.int64Value;
422 }
Ray Essick3938dc62016-11-01 08:56:56 -0700423 return true;
424}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800425
426bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
427 Prop *prop = findProp(name);
428 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700429 return false;
430 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800431 if (count != NULL) {
432 *count = prop->u.rate.count;
433 }
434 if (duration != NULL) {
435 *duration = prop->u.rate.duration;
436 }
437 if (rate != NULL) {
438 double r = 0.0;
439 if (prop->u.rate.duration != 0) {
440 r = prop->u.rate.count / (double) prop->u.rate.duration;
441 }
442 *rate = r;
443 }
444 return true;
445}
446
447bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
448 Prop *prop = findProp(name);
449 if (prop == NULL || prop->mType != kTypeDouble) {
450 return false;
451 }
452 if (value != NULL) {
453 *value = prop->u.doubleValue;
454 }
Ray Essick3938dc62016-11-01 08:56:56 -0700455 return true;
456}
457
458// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800459bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
460 Prop *prop = findProp(name);
Ray Essick9db7b812018-11-15 12:42:19 -0800461 if (prop == NULL || prop->mType != kTypeCString) {
Ray Essick3938dc62016-11-01 08:56:56 -0700462 return false;
463 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800464 if (value != NULL) {
465 *value = strdup(prop->u.CStringValue);
466 }
Ray Essick3938dc62016-11-01 08:56:56 -0700467 return true;
468}
469
Ray Essick20147322018-11-17 09:08:39 -0800470bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
471 Prop *prop = findProp(name);
472 if (prop == NULL || prop->mType != kTypeCString) {
473 return false;
474 }
475 if (value != NULL) {
476 // std::string makes a copy for us
477 *value = prop->u.CStringValue;
478 }
479 return true;
480}
481
Ray Essick3938dc62016-11-01 08:56:56 -0700482// remove indicated keys and their values
483// return value is # keys removed
484int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
485 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800486 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700487 return -1;
488 }
489 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800490 const char *name = attrs[i];
491 size_t len = strlen(name);
492 size_t j = findPropIndex(name, len);
493 if (j >= mPropCount) {
494 // not there
495 continue;
496 } else if (j+1 == mPropCount) {
497 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700498 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800499 clearProp(&mProps[j]);
500 mPropCount--;
501 } else {
502 // in the middle, bring last one down and shorten
503 zapped++;
504 clearProp(&mProps[j]);
505 mProps[j] = mProps[mPropCount-1];
506 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700507 }
508 }
509 return zapped;
510}
511
512// remove any keys NOT in the provided list
513// return value is # keys removed
514int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
515 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800516 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700517 return -1;
518 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800519 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
520 Prop *prop = &mProps[i];
521 for (ssize_t j = 0; j < n ; j++) {
522 if (strcmp(prop->mName, attrs[j]) == 0) {
523 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700524 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800525 if (i != (ssize_t)(mPropCount-1)) {
526 *prop = mProps[mPropCount-1];
527 }
528 initProp(&mProps[mPropCount-1]);
529 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700530 break;
531 }
532 }
533 }
534 return zapped;
535}
536
537// remove a single key
538// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800539int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
540 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700541}
542
Ray Essick3938dc62016-11-01 08:56:56 -0700543// handle individual items/properties stored within the class
544//
Ray Essick3938dc62016-11-01 08:56:56 -0700545
Ray Essickb5fac8e2016-12-12 11:33:56 -0800546void MediaAnalyticsItem::initProp(Prop *prop) {
547 if (prop != NULL) {
548 prop->mName = NULL;
549 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700550
Ray Essickb5fac8e2016-12-12 11:33:56 -0800551 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700552 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800553}
554
555void MediaAnalyticsItem::clearProp(Prop *prop)
556{
557 if (prop != NULL) {
558 if (prop->mName != NULL) {
559 free((void *)prop->mName);
560 prop->mName = NULL;
561 prop->mNameLen = 0;
562 }
563
564 clearPropValue(prop);
565 }
566}
567
568void MediaAnalyticsItem::clearPropValue(Prop *prop)
569{
570 if (prop != NULL) {
571 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
572 free(prop->u.CStringValue);
573 prop->u.CStringValue = NULL;
574 }
575 prop->mType = kTypeNone;
576 }
577}
578
579void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
580{
581 // get rid of any pointers in the dst
582 clearProp(dst);
583
584 *dst = *src;
585
586 // fix any pointers that we blindly copied, so we have our own copies
587 if (dst->mName) {
588 void *p = malloc(dst->mNameLen + 1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700589 LOG_ALWAYS_FATAL_IF(p == NULL,
590 "failed malloc() duping property '%s' (len %zu)",
591 dst->mName, dst->mNameLen);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800592 memcpy (p, src->mName, dst->mNameLen + 1);
593 dst->mName = (const char *) p;
594 }
595 if (dst->mType == kTypeCString) {
596 dst->u.CStringValue = strdup(src->u.CStringValue);
597 }
598}
599
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700600bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800601{
602 if (increment <= 0) {
603 increment = kGrowProps;
604 }
605 int nsize = mPropSize + increment;
606 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
607
608 if (ni != NULL) {
609 for (int i = mPropSize; i < nsize; i++) {
610 initProp(&ni[i]);
611 }
612 mProps = ni;
613 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700614 return true;
615 } else {
616 ALOGW("MediaAnalyticsItem::growProps fails");
617 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800618 }
Ray Essick3938dc62016-11-01 08:56:56 -0700619}
620
621// Parcel / serialize things for binder calls
622//
623
624int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800625 int32_t version = data.readInt32();
626
627 switch(version) {
628 case 0:
629 return readFromParcel0(data);
630 break;
631 default:
632 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
633 return -1;
634 }
635}
636
637int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700638 // into 'this' object
639 // .. we make a copy of the string to put away.
640 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700641 mPid = data.readInt32();
642 mUid = data.readInt32();
643 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800644 mPkgVersionCode = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800645 // We no longer pay attention to user setting of finalized, BUT it's
646 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700647 mTimestamp = data.readInt64();
648
649 int count = data.readInt32();
650 for (int i = 0; i < count ; i++) {
651 MediaAnalyticsItem::Attr attr = data.readCString();
652 int32_t ztype = data.readInt32();
653 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800654 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700655 setInt32(attr, data.readInt32());
656 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800657 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700658 setInt64(attr, data.readInt64());
659 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800660 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700661 setDouble(attr, data.readDouble());
662 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800663 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700664 setCString(attr, data.readCString());
665 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800666 case MediaAnalyticsItem::kTypeRate:
667 {
668 int64_t count = data.readInt64();
669 int64_t duration = data.readInt64();
670 setRate(attr, count, duration);
671 }
672 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700673 default:
674 ALOGE("reading bad item type: %d, idx %d",
675 ztype, i);
676 return -1;
677 }
678 }
679
680 return 0;
681}
682
683int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800684
Ray Essick3938dc62016-11-01 08:56:56 -0700685 if (data == NULL) return -1;
686
Ray Essickba8c4842019-01-18 11:35:33 -0800687 int32_t version = 0;
688 data->writeInt32(version);
689
690 switch(version) {
691 case 0:
692 return writeToParcel0(data);
693 break;
694 default:
695 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
696 return -1;
697 }
698}
699
700int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700701
702 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700703 data->writeInt32(mPid);
704 data->writeInt32(mUid);
705 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800706 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700707 data->writeInt64(mTimestamp);
708
709 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800710 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700711 data->writeInt32(count);
712 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800713 Prop *prop = &mProps[i];
714 data->writeCString(prop->mName);
715 data->writeInt32(prop->mType);
716 switch (prop->mType) {
717 case MediaAnalyticsItem::kTypeInt32:
718 data->writeInt32(prop->u.int32Value);
719 break;
720 case MediaAnalyticsItem::kTypeInt64:
721 data->writeInt64(prop->u.int64Value);
722 break;
723 case MediaAnalyticsItem::kTypeDouble:
724 data->writeDouble(prop->u.doubleValue);
725 break;
726 case MediaAnalyticsItem::kTypeRate:
727 data->writeInt64(prop->u.rate.count);
728 data->writeInt64(prop->u.rate.duration);
729 break;
730 case MediaAnalyticsItem::kTypeCString:
731 data->writeCString(prop->u.CStringValue);
732 break;
733 default:
734 ALOGE("found bad Prop type: %d, idx %d, name %s",
735 prop->mType, i, prop->mName);
736 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700737 }
738 }
739
740 return 0;
741}
742
Ray Essick20147322018-11-17 09:08:39 -0800743const char *MediaAnalyticsItem::toCString() {
744 return toCString(PROTO_LAST);
745}
746
747const char * MediaAnalyticsItem::toCString(int version) {
748 std::string val = toString(version);
749 return strdup(val.c_str());
750}
751
Andy Hung17dbaf22019-10-11 14:06:31 -0700752std::string MediaAnalyticsItem::toString() const {
Ray Essick5b77bd22018-01-23 16:11:06 -0800753 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700754}
Ray Essick3938dc62016-11-01 08:56:56 -0700755
Andy Hung17dbaf22019-10-11 14:06:31 -0700756std::string MediaAnalyticsItem::toString(int version) const {
Ray Essickf65f4212017-08-31 11:41:19 -0700757
758 // v0 : released with 'o'
759 // v1 : bug fix (missing pid/finalized separator),
760 // adds apk name, apk version code
761
762 if (version <= PROTO_FIRST) {
763 // default to original v0 format, until proper parsers are in place
764 version = PROTO_V0;
765 } else if (version > PROTO_LAST) {
766 version = PROTO_LAST;
767 }
768
Ray Essick783bd0d2018-01-11 11:10:35 -0800769 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800770 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700771
Ray Essickf65f4212017-08-31 11:41:19 -0700772 if (version == PROTO_V0) {
773 result = "(";
774 } else {
775 snprintf(buffer, sizeof(buffer), "[%d:", version);
776 result.append(buffer);
777 }
778
Ray Essick3938dc62016-11-01 08:56:56 -0700779 // same order as we spill into the parcel, although not required
780 // key+session are our primary matching criteria
781 result.append(mKey.c_str());
Andy Hunga87e69c2019-10-18 10:07:40 -0700782 result.append(":0:"); // sessionID
Ray Essick3938dc62016-11-01 08:56:56 -0700783
Ray Essickf65f4212017-08-31 11:41:19 -0700784 snprintf(buffer, sizeof(buffer), "%d:", mUid);
785 result.append(buffer);
786
787 if (version >= PROTO_V1) {
788 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800789 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700790 result.append(buffer);
791 }
792
793 // in 'o' (v1) , the separator between pid and finalized was omitted
794 if (version <= PROTO_V0) {
795 snprintf(buffer, sizeof(buffer), "%d", mPid);
796 } else {
797 snprintf(buffer, sizeof(buffer), "%d:", mPid);
798 }
Ray Essick3938dc62016-11-01 08:56:56 -0700799 result.append(buffer);
800
Andy Hunga87e69c2019-10-18 10:07:40 -0700801 snprintf(buffer, sizeof(buffer), "%d:", 0 /* finalized */); // TODO: remove this.
Ray Essick3938dc62016-11-01 08:56:56 -0700802 result.append(buffer);
803 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
804 result.append(buffer);
805
806 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800807 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700808 snprintf(buffer, sizeof(buffer), "%d:", count);
809 result.append(buffer);
810 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800811 Prop *prop = &mProps[i];
812 switch (prop->mType) {
813 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700814 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800815 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700816 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800817 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700818 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800819 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700820 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800821 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700822 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800823 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700824 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800825 case MediaAnalyticsItem::kTypeRate:
826 snprintf(buffer,sizeof(buffer),
827 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
828 prop->u.rate.count, prop->u.rate.duration);
829 break;
830 case MediaAnalyticsItem::kTypeCString:
831 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700832 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800833 // XXX: sanitize string for ':' '='
834 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700835 buffer[0] = ':';
836 buffer[1] = '\0';
837 break;
838 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800839 ALOGE("to_String bad item type: %d for %s",
840 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700841 break;
842 }
843 result.append(buffer);
844 }
845
Ray Essickf65f4212017-08-31 11:41:19 -0700846 if (version == PROTO_V0) {
847 result.append(")");
848 } else {
849 result.append("]");
850 }
Ray Essick3938dc62016-11-01 08:56:56 -0700851
852 return result;
853}
854
855// for the lazy, we offer methods that finds the service and
856// calls the appropriate daemon
857bool MediaAnalyticsItem::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700858 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700859 sp<IMediaAnalyticsService> svc = getInstance();
Ray Essick3938dc62016-11-01 08:56:56 -0700860 if (svc != NULL) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700861 status_t status = svc->submit(this);
862 if (status != NO_ERROR) {
863 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick2ab3c432017-10-02 09:29:49 -0700864 return false;
865 }
Ray Essick3938dc62016-11-01 08:56:56 -0700866 return true;
867 } else {
868 return false;
869 }
870}
871
Ray Essick3938dc62016-11-01 08:56:56 -0700872
873//static
874bool MediaAnalyticsItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700875 // completely skip logging from certain UIDs. We do this here
876 // to avoid the multi-second timeouts while we learn that
877 // sepolicy will not let us find the service.
878 // We do this only for a select set of UIDs
879 // The sepolicy protection is still in place, we just want a faster
880 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700881
Andy Hunga87e69c2019-10-18 10:07:40 -0700882 // This is checked only once in the lifetime of the process.
883 const uid_t uid = getuid();
884 switch (uid) {
885 case AID_RADIO: // telephony subsystem, RIL
886 return false;
887 }
888
889 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700890 if (enabled == -1) {
891 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
892 }
893 if (enabled == -1) {
894 enabled = MediaAnalyticsItem::EnabledProperty_default;
895 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700896 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700897}
898
Ray Essick2ab3c432017-10-02 09:29:49 -0700899// monitor health of our connection to the metrics service
900class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
901 virtual void binderDied(const wp<IBinder> &) {
902 ALOGW("Reacquire service connection on next request");
903 MediaAnalyticsItem::dropInstance();
904 }
905};
906
Andy Hunga87e69c2019-10-18 10:07:40 -0700907static sp<MediaMetricsDeathNotifier> sNotifier;
908// static
909sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
910static std::mutex sServiceMutex;
911static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700912
913// static
914void MediaAnalyticsItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700915 std::lock_guard _l(sServiceMutex);
916 sRemainingBindAttempts = SVC_TRIES;
917 sAnalyticsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700918}
919
Ray Essick3938dc62016-11-01 08:56:56 -0700920//static
921sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800922 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700923 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700924
925 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700926 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
927 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700928 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700929 std::lock_guard _l(sServiceMutex);
930 // think of remainingBindAttempts as telling us whether service == nullptr because
931 // (1) we haven't tried to initialize it yet
932 // (2) we've tried to initialize it, but failed.
933 if (sAnalyticsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700934 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700935 sp<IServiceManager> sm = defaultServiceManager();
936 if (sm != nullptr) {
937 sp<IBinder> binder = sm->getService(String16(servicename));
938 if (binder != nullptr) {
939 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
940 sNotifier = new MediaMetricsDeathNotifier();
941 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700942 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700943 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700944 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700945 } else {
946 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700947 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700948 if (sAnalyticsService == nullptr) {
949 if (sRemainingBindAttempts > 0) {
950 sRemainingBindAttempts--;
951 }
952 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
953 __func__, servicename, badness);
954 }
Ray Essick3938dc62016-11-01 08:56:56 -0700955 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700956 return sAnalyticsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700957}
958
Ray Essick3938dc62016-11-01 08:56:56 -0700959// merge the info from 'incoming' into this record.
960// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800961bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700962
963 // if I don't have key or session id, take them from incoming
964 // 'this' should never be missing both of them...
965 if (mKey.empty()) {
966 mKey = incoming->mKey;
Ray Essick3938dc62016-11-01 08:56:56 -0700967 }
968
Ray Essick3938dc62016-11-01 08:56:56 -0700969 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800970 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700971 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800972 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800973 const char *p = iprop->mName;
974 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700975
976 // should ignore a zero length name...
977 if (len == 0) {
978 continue;
979 }
980
981 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700982
Ray Essickb5fac8e2016-12-12 11:33:56 -0800983 if (oprop == NULL) {
984 // no oprop, so we insert the new one
985 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700986 if (oprop != NULL) {
987 copyProp(oprop, iprop);
988 } else {
989 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800990 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700991 } else {
992 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -0700993 }
994 }
995
996 // not sure when we'd return false...
997 return true;
998}
999
Ray Essickba8c4842019-01-18 11:35:33 -08001000// a byte array; contents are
1001// overall length (uint32) including the length field itself
1002// encoding version (uint32)
1003// count of properties (uint32)
1004// N copies of:
1005// property name as length(int16), bytes
1006// the bytes WILL include the null terminator of the name
1007// type (uint8 -- 1 byte)
1008// size of value field (int16 -- 2 bytes)
1009// value (size based on type)
1010// int32, int64, double -- little endian 4/8/8 bytes respectively
1011// cstring -- N bytes of value [WITH terminator]
1012
1013enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
1014
1015bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
1016
1017 char *build = NULL;
1018
1019 if (pbuffer == NULL || plength == NULL)
1020 return false;
1021
1022 // consistency for the caller, who owns whatever comes back in this pointer.
1023 *pbuffer = NULL;
1024
1025 // first, let's calculate sizes
1026 int32_t goal = 0;
1027 int32_t version = 0;
1028
1029 goal += sizeof(uint32_t); // overall length, including the length field
1030 goal += sizeof(uint32_t); // encoding version
1031 goal += sizeof(uint32_t); // # properties
1032
1033 int32_t count = mPropCount;
1034 for (int i = 0 ; i < count; i++ ) {
1035 Prop *prop = &mProps[i];
1036 goal += sizeof(uint16_t); // name length
1037 goal += strlen(prop->mName) + 1; // string + null
1038 goal += sizeof(uint8_t); // type
1039 goal += sizeof(uint16_t); // size of value
1040 switch (prop->mType) {
1041 case MediaAnalyticsItem::kTypeInt32:
1042 goal += sizeof(uint32_t);
1043 break;
1044 case MediaAnalyticsItem::kTypeInt64:
1045 goal += sizeof(uint64_t);
1046 break;
1047 case MediaAnalyticsItem::kTypeDouble:
1048 goal += sizeof(double);
1049 break;
1050 case MediaAnalyticsItem::kTypeRate:
1051 goal += 2 * sizeof(uint64_t);
1052 break;
1053 case MediaAnalyticsItem::kTypeCString:
1054 // length + actual string + null
1055 goal += strlen(prop->u.CStringValue) + 1;
1056 break;
1057 default:
1058 ALOGE("found bad Prop type: %d, idx %d, name %s",
1059 prop->mType, i, prop->mName);
1060 return false;
1061 }
1062 }
1063
1064 // now that we have a size... let's allocate and fill
1065 build = (char *)malloc(goal);
1066 if (build == NULL)
1067 return false;
1068
1069 memset(build, 0, goal);
1070
1071 char *filling = build;
1072
1073#define _INSERT(val, size) \
1074 { memcpy(filling, &(val), (size)); filling += (size);}
1075#define _INSERTSTRING(val, size) \
1076 { memcpy(filling, (val), (size)); filling += (size);}
1077
1078 _INSERT(goal, sizeof(int32_t));
1079 _INSERT(version, sizeof(int32_t));
1080 _INSERT(count, sizeof(int32_t));
1081
1082 for (int i = 0 ; i < count; i++ ) {
1083 Prop *prop = &mProps[i];
1084 int16_t attrNameLen = strlen(prop->mName) + 1;
1085 _INSERT(attrNameLen, sizeof(int16_t));
1086 _INSERTSTRING(prop->mName, attrNameLen); // termination included
1087 int8_t elemtype;
1088 int16_t elemsize;
1089 switch (prop->mType) {
1090 case MediaAnalyticsItem::kTypeInt32:
1091 {
1092 elemtype = kInt32;
1093 _INSERT(elemtype, sizeof(int8_t));
1094 elemsize = sizeof(int32_t);
1095 _INSERT(elemsize, sizeof(int16_t));
1096
1097 _INSERT(prop->u.int32Value, sizeof(int32_t));
1098 break;
1099 }
1100 case MediaAnalyticsItem::kTypeInt64:
1101 {
1102 elemtype = kInt64;
1103 _INSERT(elemtype, sizeof(int8_t));
1104 elemsize = sizeof(int64_t);
1105 _INSERT(elemsize, sizeof(int16_t));
1106
1107 _INSERT(prop->u.int64Value, sizeof(int64_t));
1108 break;
1109 }
1110 case MediaAnalyticsItem::kTypeDouble:
1111 {
1112 elemtype = kDouble;
1113 _INSERT(elemtype, sizeof(int8_t));
1114 elemsize = sizeof(double);
1115 _INSERT(elemsize, sizeof(int16_t));
1116
1117 _INSERT(prop->u.doubleValue, sizeof(double));
1118 break;
1119 }
1120 case MediaAnalyticsItem::kTypeRate:
1121 {
1122 elemtype = kRate;
1123 _INSERT(elemtype, sizeof(int8_t));
1124 elemsize = 2 * sizeof(uint64_t);
1125 _INSERT(elemsize, sizeof(int16_t));
1126
1127 _INSERT(prop->u.rate.count, sizeof(uint64_t));
1128 _INSERT(prop->u.rate.duration, sizeof(uint64_t));
1129 break;
1130 }
1131 case MediaAnalyticsItem::kTypeCString:
1132 {
1133 elemtype = kCString;
1134 _INSERT(elemtype, sizeof(int8_t));
1135 elemsize = strlen(prop->u.CStringValue) + 1;
1136 _INSERT(elemsize, sizeof(int16_t));
1137
1138 _INSERTSTRING(prop->u.CStringValue, elemsize);
1139 break;
1140 }
1141 default:
1142 // error if can't encode; warning if can't decode
1143 ALOGE("found bad Prop type: %d, idx %d, name %s",
1144 prop->mType, i, prop->mName);
1145 goto badness;
1146 }
1147 }
1148
1149 if (build + goal != filling) {
1150 ALOGE("problems populating; wrote=%d planned=%d",
1151 (int)(filling-build), goal);
1152 goto badness;
1153 }
1154
1155 *pbuffer = build;
1156 *plength = goal;
1157
1158 return true;
1159
1160 badness:
1161 free(build);
1162 return false;
1163}
1164
Ray Essick3938dc62016-11-01 08:56:56 -07001165} // namespace android
1166