blob: 02c23b123145e3b2c863c1ee9aa5254e75b08737 [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
25#include <binder/Parcel.h>
26#include <utils/Errors.h>
27#include <utils/Log.h>
28#include <utils/Mutex.h>
Ray Essick3938dc62016-11-01 08:56:56 -070029#include <utils/SortedVector.h>
30#include <utils/threads.h>
31
Ray Essick3938dc62016-11-01 08:56:56 -070032#include <binder/IServiceManager.h>
33#include <media/IMediaAnalyticsService.h>
34#include <media/MediaAnalyticsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070035#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070036
37namespace android {
38
39#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080040#define DEBUG_API 0
41#define DEBUG_ALLOCATIONS 0
42
43// after this many failed attempts, we stop trying [from this process] and just say that
44// the service is off.
45#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070046
47// the few universal keys we have
48const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
49const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
50
Ray Essickd38e1742017-01-23 15:17:06 -080051const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
52const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
Ray Essickd6a6c672017-01-25 14:28:51 -080053const int MediaAnalyticsItem::EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -070054
Ray Essickba8c4842019-01-18 11:35:33 -080055// So caller doesn't need to know size of allocated space
56MediaAnalyticsItem *MediaAnalyticsItem::create()
57{
58 return MediaAnalyticsItem::create(kKeyNone);
59}
60
61MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
62{
63 MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
64 return item;
65}
Ray Essick3938dc62016-11-01 08:56:56 -070066
67// access functions for the class
68MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080069 : mPid(-1),
70 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070071 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070072 mSessionID(MediaAnalyticsItem::SessionIDNone),
73 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080074 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080075 mPropCount(0), mPropSize(0), mProps(NULL)
76{
Ray Essick3938dc62016-11-01 08:56:56 -070077 mKey = MediaAnalyticsItem::kKeyNone;
78}
79
80MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080081 : mPid(-1),
82 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070083 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070084 mSessionID(MediaAnalyticsItem::SessionIDNone),
85 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080086 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080087 mPropCount(0), mPropSize(0), mProps(NULL)
88{
89 if (DEBUG_ALLOCATIONS) {
90 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
91 }
Ray Essick3938dc62016-11-01 08:56:56 -070092 mKey = key;
93}
94
95MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080096 if (DEBUG_ALLOCATIONS) {
97 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
98 }
Ray Essick3938dc62016-11-01 08:56:56 -070099 clear();
100}
101
Ray Essickb5fac8e2016-12-12 11:33:56 -0800102void MediaAnalyticsItem::clear() {
103
104 // clean allocated storage from key
105 mKey.clear();
106
Ray Essickd38e1742017-01-23 15:17:06 -0800107 // clean various major parameters
108 mSessionID = MediaAnalyticsItem::SessionIDNone;
109
Ray Essickb5fac8e2016-12-12 11:33:56 -0800110 // clean attributes
111 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700112 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800113 clearProp(&mProps[i]);
114 }
115 // the attribute records themselves
116 if (mProps != NULL) {
117 free(mProps);
118 mProps = NULL;
119 }
120 mPropSize = 0;
121 mPropCount = 0;
122
123 return;
124}
125
126// make a deep copy of myself
127MediaAnalyticsItem *MediaAnalyticsItem::dup() {
128 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
129
130 if (dst != NULL) {
131 // key as part of constructor
132 dst->mPid = this->mPid;
133 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700134 dst->mPkgName = this->mPkgName;
135 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800136 dst->mSessionID = this->mSessionID;
137 dst->mTimestamp = this->mTimestamp;
138 dst->mFinalized = this->mFinalized;
139
140 // properties aka attributes
141 dst->growProps(this->mPropCount);
142 for(size_t i=0;i<mPropCount;i++) {
143 copyProp(&dst->mProps[i], &this->mProps[i]);
144 }
145 dst->mPropCount = this->mPropCount;
146 }
147
148 return dst;
149}
150
Ray Essick3938dc62016-11-01 08:56:56 -0700151MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
152 mSessionID = id;
153 return *this;
154}
155
156MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
157 return mSessionID;
158}
159
160MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700161
162 if (mSessionID == SessionIDNone) {
163 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800164 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700165 sp<IMediaAnalyticsService> svc = getInstance();
166 if (svc != NULL) {
167 newid = svc->generateUniqueSessionID();
168 }
169 mSessionID = newid;
170 }
171
172 return mSessionID;
173}
174
175MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
176 mSessionID = MediaAnalyticsItem::SessionIDNone;
177 return *this;
178}
179
180MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
181 mTimestamp = ts;
182 return *this;
183}
184
185nsecs_t MediaAnalyticsItem::getTimestamp() const {
186 return mTimestamp;
187}
188
189MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
190 mPid = pid;
191 return *this;
192}
193
194pid_t MediaAnalyticsItem::getPid() const {
195 return mPid;
196}
197
198MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
199 mUid = uid;
200 return *this;
201}
202
203uid_t MediaAnalyticsItem::getUid() const {
204 return mUid;
205}
206
Ray Essick783bd0d2018-01-11 11:10:35 -0800207MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700208 mPkgName = pkgName;
209 return *this;
210}
211
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800212MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700213 mPkgVersionCode = pkgVersionCode;
214 return *this;
215}
216
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800217int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700218 return mPkgVersionCode;
219}
220
Ray Essickb5fac8e2016-12-12 11:33:56 -0800221// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700222MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700223 mKey = key;
224 return *this;
225}
226
227MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
228 return mKey;
229}
230
Ray Essickb5fac8e2016-12-12 11:33:56 -0800231// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700232int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800233 return mPropCount;
234}
235
236// find the proper entry in the list
237size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
238{
239 size_t i = 0;
240 for (; i < mPropCount; i++) {
241 Prop *prop = &mProps[i];
242 if (prop->mNameLen != len) {
243 continue;
244 }
245 if (memcmp(name, prop->mName, len) == 0) {
246 break;
247 }
248 }
249 return i;
250}
251
252MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
253 size_t len = strlen(name);
254 size_t i = findPropIndex(name, len);
255 if (i < mPropCount) {
256 return &mProps[i];
257 }
258 return NULL;
259}
260
261void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700262 free((void *)mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800263 mName = (const char *) malloc(len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700264 LOG_ALWAYS_FATAL_IF(mName == NULL,
265 "failed malloc() for property '%s' (len %zu)",
266 name, len);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800267 memcpy ((void *)mName, name, len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700268 mNameLen = len;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800269}
270
Ray Essick9ce18f72018-05-07 15:54:30 -0700271// consider this "find-or-allocate".
272// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800273MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
274 size_t len = strlen(name);
275 size_t i = findPropIndex(name, len);
276 Prop *prop;
277
278 if (i < mPropCount) {
279 prop = &mProps[i];
280 } else {
281 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700282 if (growProps() == false) {
283 ALOGE("failed allocation for new props");
284 return NULL;
285 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800286 }
287 i = mPropCount++;
288 prop = &mProps[i];
289 prop->setName(name, len);
290 }
291
292 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700293}
294
Ray Essickf65f4212017-08-31 11:41:19 -0700295// used within the summarizers; return whether property existed
296bool MediaAnalyticsItem::removeProp(const char *name) {
297 size_t len = strlen(name);
298 size_t i = findPropIndex(name, len);
299 if (i < mPropCount) {
300 Prop *prop = &mProps[i];
301 clearProp(prop);
302 if (i != mPropCount-1) {
303 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700304 copyProp(prop, &mProps[mPropCount-1]);
305 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700306 }
307 mPropCount--;
308 return true;
309 }
310 return false;
311}
312
Ray Essick3938dc62016-11-01 08:56:56 -0700313// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800314void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
315 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700316 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700317 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700318 prop->mType = kTypeInt32;
319 prop->u.int32Value = value;
320 }
Ray Essick3938dc62016-11-01 08:56:56 -0700321}
322
Ray Essickb5fac8e2016-12-12 11:33:56 -0800323void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
324 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700325 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700326 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700327 prop->mType = kTypeInt64;
328 prop->u.int64Value = value;
329 }
Ray Essick3938dc62016-11-01 08:56:56 -0700330}
331
Ray Essickb5fac8e2016-12-12 11:33:56 -0800332void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
333 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700334 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700335 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700336 prop->mType = kTypeDouble;
337 prop->u.doubleValue = value;
338 }
Ray Essick3938dc62016-11-01 08:56:56 -0700339}
340
Ray Essickb5fac8e2016-12-12 11:33:56 -0800341void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
342
343 Prop *prop = allocateProp(name);
344 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700345 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700346 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700347 prop->mType = kTypeCString;
348 prop->u.CStringValue = strdup(value);
349 }
Ray Essick3938dc62016-11-01 08:56:56 -0700350}
351
Ray Essickb5fac8e2016-12-12 11:33:56 -0800352void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
353 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700354 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700355 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700356 prop->mType = kTypeRate;
357 prop->u.rate.count = count;
358 prop->u.rate.duration = duration;
359 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800360}
361
362
Ray Essick3938dc62016-11-01 08:56:56 -0700363// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800364void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
365 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700366 if (prop == NULL) {
367 return;
368 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800369 switch (prop->mType) {
370 case kTypeInt32:
371 prop->u.int32Value += value;
372 break;
373 default:
374 clearPropValue(prop);
375 prop->mType = kTypeInt32;
376 prop->u.int32Value = value;
377 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700378 }
Ray Essick3938dc62016-11-01 08:56:56 -0700379}
380
Ray Essickb5fac8e2016-12-12 11:33:56 -0800381void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
382 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700383 if (prop == NULL) {
384 return;
385 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800386 switch (prop->mType) {
387 case kTypeInt64:
388 prop->u.int64Value += value;
389 break;
390 default:
391 clearPropValue(prop);
392 prop->mType = kTypeInt64;
393 prop->u.int64Value = value;
394 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700395 }
Ray Essick3938dc62016-11-01 08:56:56 -0700396}
397
Ray Essickb5fac8e2016-12-12 11:33:56 -0800398void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
399 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700400 if (prop == NULL) {
401 return;
402 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800403 switch (prop->mType) {
404 case kTypeRate:
405 prop->u.rate.count += count;
406 prop->u.rate.duration += duration;
407 break;
408 default:
409 clearPropValue(prop);
410 prop->mType = kTypeRate;
411 prop->u.rate.count = count;
412 prop->u.rate.duration = duration;
413 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700414 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800415}
416
417void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
418 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700419 if (prop == NULL) {
420 return;
421 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800422 switch (prop->mType) {
423 case kTypeDouble:
424 prop->u.doubleValue += value;
425 break;
426 default:
427 clearPropValue(prop);
428 prop->mType = kTypeDouble;
429 prop->u.doubleValue = value;
430 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700431 }
Ray Essick3938dc62016-11-01 08:56:56 -0700432}
433
434// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800435bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
436 Prop *prop = findProp(name);
437 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700438 return false;
439 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800440 if (value != NULL) {
441 *value = prop->u.int32Value;
442 }
Ray Essick3938dc62016-11-01 08:56:56 -0700443 return true;
444}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800445
446bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
447 Prop *prop = findProp(name);
448 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700449 return false;
450 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800451 if (value != NULL) {
452 *value = prop->u.int64Value;
453 }
Ray Essick3938dc62016-11-01 08:56:56 -0700454 return true;
455}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800456
457bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
458 Prop *prop = findProp(name);
459 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700460 return false;
461 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800462 if (count != NULL) {
463 *count = prop->u.rate.count;
464 }
465 if (duration != NULL) {
466 *duration = prop->u.rate.duration;
467 }
468 if (rate != NULL) {
469 double r = 0.0;
470 if (prop->u.rate.duration != 0) {
471 r = prop->u.rate.count / (double) prop->u.rate.duration;
472 }
473 *rate = r;
474 }
475 return true;
476}
477
478bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
479 Prop *prop = findProp(name);
480 if (prop == NULL || prop->mType != kTypeDouble) {
481 return false;
482 }
483 if (value != NULL) {
484 *value = prop->u.doubleValue;
485 }
Ray Essick3938dc62016-11-01 08:56:56 -0700486 return true;
487}
488
489// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800490bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
491 Prop *prop = findProp(name);
Ray Essick9db7b812018-11-15 12:42:19 -0800492 if (prop == NULL || prop->mType != kTypeCString) {
Ray Essick3938dc62016-11-01 08:56:56 -0700493 return false;
494 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800495 if (value != NULL) {
496 *value = strdup(prop->u.CStringValue);
497 }
Ray Essick3938dc62016-11-01 08:56:56 -0700498 return true;
499}
500
Ray Essick20147322018-11-17 09:08:39 -0800501bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
502 Prop *prop = findProp(name);
503 if (prop == NULL || prop->mType != kTypeCString) {
504 return false;
505 }
506 if (value != NULL) {
507 // std::string makes a copy for us
508 *value = prop->u.CStringValue;
509 }
510 return true;
511}
512
Ray Essick3938dc62016-11-01 08:56:56 -0700513// remove indicated keys and their values
514// return value is # keys removed
515int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
516 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800517 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700518 return -1;
519 }
520 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800521 const char *name = attrs[i];
522 size_t len = strlen(name);
523 size_t j = findPropIndex(name, len);
524 if (j >= mPropCount) {
525 // not there
526 continue;
527 } else if (j+1 == mPropCount) {
528 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700529 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800530 clearProp(&mProps[j]);
531 mPropCount--;
532 } else {
533 // in the middle, bring last one down and shorten
534 zapped++;
535 clearProp(&mProps[j]);
536 mProps[j] = mProps[mPropCount-1];
537 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700538 }
539 }
540 return zapped;
541}
542
543// remove any keys NOT in the provided list
544// return value is # keys removed
545int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
546 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800547 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700548 return -1;
549 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800550 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
551 Prop *prop = &mProps[i];
552 for (ssize_t j = 0; j < n ; j++) {
553 if (strcmp(prop->mName, attrs[j]) == 0) {
554 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700555 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800556 if (i != (ssize_t)(mPropCount-1)) {
557 *prop = mProps[mPropCount-1];
558 }
559 initProp(&mProps[mPropCount-1]);
560 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700561 break;
562 }
563 }
564 }
565 return zapped;
566}
567
568// remove a single key
569// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800570int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
571 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700572}
573
Ray Essick3938dc62016-11-01 08:56:56 -0700574// handle individual items/properties stored within the class
575//
Ray Essick3938dc62016-11-01 08:56:56 -0700576
Ray Essickb5fac8e2016-12-12 11:33:56 -0800577void MediaAnalyticsItem::initProp(Prop *prop) {
578 if (prop != NULL) {
579 prop->mName = NULL;
580 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700581
Ray Essickb5fac8e2016-12-12 11:33:56 -0800582 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700583 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800584}
585
586void MediaAnalyticsItem::clearProp(Prop *prop)
587{
588 if (prop != NULL) {
589 if (prop->mName != NULL) {
590 free((void *)prop->mName);
591 prop->mName = NULL;
592 prop->mNameLen = 0;
593 }
594
595 clearPropValue(prop);
596 }
597}
598
599void MediaAnalyticsItem::clearPropValue(Prop *prop)
600{
601 if (prop != NULL) {
602 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
603 free(prop->u.CStringValue);
604 prop->u.CStringValue = NULL;
605 }
606 prop->mType = kTypeNone;
607 }
608}
609
610void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
611{
612 // get rid of any pointers in the dst
613 clearProp(dst);
614
615 *dst = *src;
616
617 // fix any pointers that we blindly copied, so we have our own copies
618 if (dst->mName) {
619 void *p = malloc(dst->mNameLen + 1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700620 LOG_ALWAYS_FATAL_IF(p == NULL,
621 "failed malloc() duping property '%s' (len %zu)",
622 dst->mName, dst->mNameLen);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800623 memcpy (p, src->mName, dst->mNameLen + 1);
624 dst->mName = (const char *) p;
625 }
626 if (dst->mType == kTypeCString) {
627 dst->u.CStringValue = strdup(src->u.CStringValue);
628 }
629}
630
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700631bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800632{
633 if (increment <= 0) {
634 increment = kGrowProps;
635 }
636 int nsize = mPropSize + increment;
637 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
638
639 if (ni != NULL) {
640 for (int i = mPropSize; i < nsize; i++) {
641 initProp(&ni[i]);
642 }
643 mProps = ni;
644 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700645 return true;
646 } else {
647 ALOGW("MediaAnalyticsItem::growProps fails");
648 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800649 }
Ray Essick3938dc62016-11-01 08:56:56 -0700650}
651
652// Parcel / serialize things for binder calls
653//
654
655int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800656 int32_t version = data.readInt32();
657
658 switch(version) {
659 case 0:
660 return readFromParcel0(data);
661 break;
662 default:
663 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
664 return -1;
665 }
666}
667
668int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700669 // into 'this' object
670 // .. we make a copy of the string to put away.
671 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700672 mPid = data.readInt32();
673 mUid = data.readInt32();
674 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800675 mPkgVersionCode = data.readInt64();
Ray Essick3938dc62016-11-01 08:56:56 -0700676 mSessionID = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800677 // We no longer pay attention to user setting of finalized, BUT it's
678 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700679 mFinalized = data.readInt32();
Ray Essick92d23b42018-01-29 12:10:30 -0800680 mFinalized = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700681 mTimestamp = data.readInt64();
682
683 int count = data.readInt32();
684 for (int i = 0; i < count ; i++) {
685 MediaAnalyticsItem::Attr attr = data.readCString();
686 int32_t ztype = data.readInt32();
687 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800688 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700689 setInt32(attr, data.readInt32());
690 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800691 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700692 setInt64(attr, data.readInt64());
693 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800694 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700695 setDouble(attr, data.readDouble());
696 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800697 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700698 setCString(attr, data.readCString());
699 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800700 case MediaAnalyticsItem::kTypeRate:
701 {
702 int64_t count = data.readInt64();
703 int64_t duration = data.readInt64();
704 setRate(attr, count, duration);
705 }
706 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700707 default:
708 ALOGE("reading bad item type: %d, idx %d",
709 ztype, i);
710 return -1;
711 }
712 }
713
714 return 0;
715}
716
717int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800718
Ray Essick3938dc62016-11-01 08:56:56 -0700719 if (data == NULL) return -1;
720
Ray Essickba8c4842019-01-18 11:35:33 -0800721 int32_t version = 0;
722 data->writeInt32(version);
723
724 switch(version) {
725 case 0:
726 return writeToParcel0(data);
727 break;
728 default:
729 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
730 return -1;
731 }
732}
733
734int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700735
736 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700737 data->writeInt32(mPid);
738 data->writeInt32(mUid);
739 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800740 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700741 data->writeInt64(mSessionID);
742 data->writeInt32(mFinalized);
743 data->writeInt64(mTimestamp);
744
745 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800746 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700747 data->writeInt32(count);
748 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800749 Prop *prop = &mProps[i];
750 data->writeCString(prop->mName);
751 data->writeInt32(prop->mType);
752 switch (prop->mType) {
753 case MediaAnalyticsItem::kTypeInt32:
754 data->writeInt32(prop->u.int32Value);
755 break;
756 case MediaAnalyticsItem::kTypeInt64:
757 data->writeInt64(prop->u.int64Value);
758 break;
759 case MediaAnalyticsItem::kTypeDouble:
760 data->writeDouble(prop->u.doubleValue);
761 break;
762 case MediaAnalyticsItem::kTypeRate:
763 data->writeInt64(prop->u.rate.count);
764 data->writeInt64(prop->u.rate.duration);
765 break;
766 case MediaAnalyticsItem::kTypeCString:
767 data->writeCString(prop->u.CStringValue);
768 break;
769 default:
770 ALOGE("found bad Prop type: %d, idx %d, name %s",
771 prop->mType, i, prop->mName);
772 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700773 }
774 }
775
776 return 0;
777}
778
Ray Essick20147322018-11-17 09:08:39 -0800779const char *MediaAnalyticsItem::toCString() {
780 return toCString(PROTO_LAST);
781}
782
783const char * MediaAnalyticsItem::toCString(int version) {
784 std::string val = toString(version);
785 return strdup(val.c_str());
786}
787
Ray Essick783bd0d2018-01-11 11:10:35 -0800788std::string MediaAnalyticsItem::toString() {
Ray Essick5b77bd22018-01-23 16:11:06 -0800789 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700790}
Ray Essick3938dc62016-11-01 08:56:56 -0700791
Ray Essick783bd0d2018-01-11 11:10:35 -0800792std::string MediaAnalyticsItem::toString(int version) {
Ray Essickf65f4212017-08-31 11:41:19 -0700793
794 // v0 : released with 'o'
795 // v1 : bug fix (missing pid/finalized separator),
796 // adds apk name, apk version code
797
798 if (version <= PROTO_FIRST) {
799 // default to original v0 format, until proper parsers are in place
800 version = PROTO_V0;
801 } else if (version > PROTO_LAST) {
802 version = PROTO_LAST;
803 }
804
Ray Essick783bd0d2018-01-11 11:10:35 -0800805 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800806 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700807
Ray Essickf65f4212017-08-31 11:41:19 -0700808 if (version == PROTO_V0) {
809 result = "(";
810 } else {
811 snprintf(buffer, sizeof(buffer), "[%d:", version);
812 result.append(buffer);
813 }
814
Ray Essick3938dc62016-11-01 08:56:56 -0700815 // same order as we spill into the parcel, although not required
816 // key+session are our primary matching criteria
817 result.append(mKey.c_str());
818 result.append(":");
819 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
820 result.append(buffer);
821
Ray Essickf65f4212017-08-31 11:41:19 -0700822 snprintf(buffer, sizeof(buffer), "%d:", mUid);
823 result.append(buffer);
824
825 if (version >= PROTO_V1) {
826 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800827 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700828 result.append(buffer);
829 }
830
831 // in 'o' (v1) , the separator between pid and finalized was omitted
832 if (version <= PROTO_V0) {
833 snprintf(buffer, sizeof(buffer), "%d", mPid);
834 } else {
835 snprintf(buffer, sizeof(buffer), "%d:", mPid);
836 }
Ray Essick3938dc62016-11-01 08:56:56 -0700837 result.append(buffer);
838
839 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
840 result.append(buffer);
841 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
842 result.append(buffer);
843
844 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800845 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700846 snprintf(buffer, sizeof(buffer), "%d:", count);
847 result.append(buffer);
848 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800849 Prop *prop = &mProps[i];
850 switch (prop->mType) {
851 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700852 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800853 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700854 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800855 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700856 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800857 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700858 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800859 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700860 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800861 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700862 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800863 case MediaAnalyticsItem::kTypeRate:
864 snprintf(buffer,sizeof(buffer),
865 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
866 prop->u.rate.count, prop->u.rate.duration);
867 break;
868 case MediaAnalyticsItem::kTypeCString:
869 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700870 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800871 // XXX: sanitize string for ':' '='
872 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700873 buffer[0] = ':';
874 buffer[1] = '\0';
875 break;
876 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800877 ALOGE("to_String bad item type: %d for %s",
878 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700879 break;
880 }
881 result.append(buffer);
882 }
883
Ray Essickf65f4212017-08-31 11:41:19 -0700884 if (version == PROTO_V0) {
885 result.append(")");
886 } else {
887 result.append("]");
888 }
Ray Essick3938dc62016-11-01 08:56:56 -0700889
890 return result;
891}
892
893// for the lazy, we offer methods that finds the service and
894// calls the appropriate daemon
895bool MediaAnalyticsItem::selfrecord() {
896 return selfrecord(false);
897}
898
899bool MediaAnalyticsItem::selfrecord(bool forcenew) {
900
Ray Essickb5fac8e2016-12-12 11:33:56 -0800901 if (DEBUG_API) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800902 std::string p = this->toString();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800903 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
904 }
Ray Essick3938dc62016-11-01 08:56:56 -0700905
906 sp<IMediaAnalyticsService> svc = getInstance();
907
908 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700909 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
910 if (newid == SessionIDInvalid) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800911 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700912 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
913 return false;
914 }
Ray Essick3938dc62016-11-01 08:56:56 -0700915 return true;
916 } else {
917 return false;
918 }
919}
920
921// get a connection we can reuse for most of our lifetime
922// static
923sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
924static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700925static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700926
927//static
928bool MediaAnalyticsItem::isEnabled() {
929 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
930
931 if (enabled == -1) {
932 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
933 }
934 if (enabled == -1) {
935 enabled = MediaAnalyticsItem::EnabledProperty_default;
936 }
937 if (enabled <= 0) {
938 return false;
939 }
940 return true;
941}
942
Ray Essick2ab3c432017-10-02 09:29:49 -0700943
944// monitor health of our connection to the metrics service
945class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
946 virtual void binderDied(const wp<IBinder> &) {
947 ALOGW("Reacquire service connection on next request");
948 MediaAnalyticsItem::dropInstance();
949 }
950};
951
952static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
953
954// static
955void MediaAnalyticsItem::dropInstance() {
956 Mutex::Autolock _l(sInitMutex);
957 remainingBindAttempts = SVC_TRIES;
958 sAnalyticsService = NULL;
959}
960
Ray Essick3938dc62016-11-01 08:56:56 -0700961//static
962sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700963
Ray Essickd38e1742017-01-23 15:17:06 -0800964 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700965 int enabled = isEnabled();
966
967 if (enabled == false) {
968 if (DEBUG_SERVICEACCESS) {
969 ALOGD("disabled");
970 }
971 return NULL;
972 }
973
Ray Essick79a89ef2017-04-24 15:52:54 -0700974 // completely skip logging from certain UIDs. We do this here
975 // to avoid the multi-second timeouts while we learn that
976 // sepolicy will not let us find the service.
977 // We do this only for a select set of UIDs
978 // The sepolicy protection is still in place, we just want a faster
979 // response from this specific, small set of uids.
980 {
981 uid_t uid = getuid();
982 switch (uid) {
983 case AID_RADIO: // telephony subsystem, RIL
984 return NULL;
985 break;
986 default:
987 // let sepolicy deny access if appropriate
988 break;
989 }
990 }
991
Ray Essick3938dc62016-11-01 08:56:56 -0700992 {
993 Mutex::Autolock _l(sInitMutex);
994 const char *badness = "";
995
Ray Essick2ab3c432017-10-02 09:29:49 -0700996 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -0800997 // (1) we haven't tried to initialize it yet
998 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -0700999 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -07001000 sp<IServiceManager> sm = defaultServiceManager();
1001 if (sm != NULL) {
1002 sp<IBinder> binder = sm->getService(String16(servicename));
1003 if (binder != NULL) {
1004 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -07001005 if (sNotifier != NULL) {
1006 sNotifier = NULL;
1007 }
1008 sNotifier = new MediaMetricsDeathNotifier();
1009 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -07001010 } else {
1011 badness = "did not find service";
1012 }
1013 } else {
1014 badness = "No Service Manager access";
1015 }
Ray Essickb5fac8e2016-12-12 11:33:56 -08001016
1017 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -07001018 if (remainingBindAttempts > 0) {
1019 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -08001020 }
1021 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -07001022 ALOGD("Unable to bind to service %s: %s", servicename, badness);
1023 }
1024 }
1025 }
Ray Essickb5fac8e2016-12-12 11:33:56 -08001026
Ray Essick3938dc62016-11-01 08:56:56 -07001027 return sAnalyticsService;
1028 }
1029}
1030
Ray Essick3938dc62016-11-01 08:56:56 -07001031// merge the info from 'incoming' into this record.
1032// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -08001033bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -07001034
1035 // if I don't have key or session id, take them from incoming
1036 // 'this' should never be missing both of them...
1037 if (mKey.empty()) {
1038 mKey = incoming->mKey;
1039 } else if (mSessionID == 0) {
1040 mSessionID = incoming->mSessionID;
1041 }
1042
Ray Essick3938dc62016-11-01 08:56:56 -07001043 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -08001044 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -07001045 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -08001046 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -08001047 const char *p = iprop->mName;
1048 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001049
1050 // should ignore a zero length name...
1051 if (len == 0) {
1052 continue;
1053 }
1054
1055 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -07001056
Ray Essickb5fac8e2016-12-12 11:33:56 -08001057 if (oprop == NULL) {
1058 // no oprop, so we insert the new one
1059 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001060 if (oprop != NULL) {
1061 copyProp(oprop, iprop);
1062 } else {
1063 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -08001064 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001065 } else {
1066 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -07001067 }
1068 }
1069
1070 // not sure when we'd return false...
1071 return true;
1072}
1073
Ray Essickba8c4842019-01-18 11:35:33 -08001074// a byte array; contents are
1075// overall length (uint32) including the length field itself
1076// encoding version (uint32)
1077// count of properties (uint32)
1078// N copies of:
1079// property name as length(int16), bytes
1080// the bytes WILL include the null terminator of the name
1081// type (uint8 -- 1 byte)
1082// size of value field (int16 -- 2 bytes)
1083// value (size based on type)
1084// int32, int64, double -- little endian 4/8/8 bytes respectively
1085// cstring -- N bytes of value [WITH terminator]
1086
1087enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
1088
1089bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
1090
1091 char *build = NULL;
1092
1093 if (pbuffer == NULL || plength == NULL)
1094 return false;
1095
1096 // consistency for the caller, who owns whatever comes back in this pointer.
1097 *pbuffer = NULL;
1098
1099 // first, let's calculate sizes
1100 int32_t goal = 0;
1101 int32_t version = 0;
1102
1103 goal += sizeof(uint32_t); // overall length, including the length field
1104 goal += sizeof(uint32_t); // encoding version
1105 goal += sizeof(uint32_t); // # properties
1106
1107 int32_t count = mPropCount;
1108 for (int i = 0 ; i < count; i++ ) {
1109 Prop *prop = &mProps[i];
1110 goal += sizeof(uint16_t); // name length
1111 goal += strlen(prop->mName) + 1; // string + null
1112 goal += sizeof(uint8_t); // type
1113 goal += sizeof(uint16_t); // size of value
1114 switch (prop->mType) {
1115 case MediaAnalyticsItem::kTypeInt32:
1116 goal += sizeof(uint32_t);
1117 break;
1118 case MediaAnalyticsItem::kTypeInt64:
1119 goal += sizeof(uint64_t);
1120 break;
1121 case MediaAnalyticsItem::kTypeDouble:
1122 goal += sizeof(double);
1123 break;
1124 case MediaAnalyticsItem::kTypeRate:
1125 goal += 2 * sizeof(uint64_t);
1126 break;
1127 case MediaAnalyticsItem::kTypeCString:
1128 // length + actual string + null
1129 goal += strlen(prop->u.CStringValue) + 1;
1130 break;
1131 default:
1132 ALOGE("found bad Prop type: %d, idx %d, name %s",
1133 prop->mType, i, prop->mName);
1134 return false;
1135 }
1136 }
1137
1138 // now that we have a size... let's allocate and fill
1139 build = (char *)malloc(goal);
1140 if (build == NULL)
1141 return false;
1142
1143 memset(build, 0, goal);
1144
1145 char *filling = build;
1146
1147#define _INSERT(val, size) \
1148 { memcpy(filling, &(val), (size)); filling += (size);}
1149#define _INSERTSTRING(val, size) \
1150 { memcpy(filling, (val), (size)); filling += (size);}
1151
1152 _INSERT(goal, sizeof(int32_t));
1153 _INSERT(version, sizeof(int32_t));
1154 _INSERT(count, sizeof(int32_t));
1155
1156 for (int i = 0 ; i < count; i++ ) {
1157 Prop *prop = &mProps[i];
1158 int16_t attrNameLen = strlen(prop->mName) + 1;
1159 _INSERT(attrNameLen, sizeof(int16_t));
1160 _INSERTSTRING(prop->mName, attrNameLen); // termination included
1161 int8_t elemtype;
1162 int16_t elemsize;
1163 switch (prop->mType) {
1164 case MediaAnalyticsItem::kTypeInt32:
1165 {
1166 elemtype = kInt32;
1167 _INSERT(elemtype, sizeof(int8_t));
1168 elemsize = sizeof(int32_t);
1169 _INSERT(elemsize, sizeof(int16_t));
1170
1171 _INSERT(prop->u.int32Value, sizeof(int32_t));
1172 break;
1173 }
1174 case MediaAnalyticsItem::kTypeInt64:
1175 {
1176 elemtype = kInt64;
1177 _INSERT(elemtype, sizeof(int8_t));
1178 elemsize = sizeof(int64_t);
1179 _INSERT(elemsize, sizeof(int16_t));
1180
1181 _INSERT(prop->u.int64Value, sizeof(int64_t));
1182 break;
1183 }
1184 case MediaAnalyticsItem::kTypeDouble:
1185 {
1186 elemtype = kDouble;
1187 _INSERT(elemtype, sizeof(int8_t));
1188 elemsize = sizeof(double);
1189 _INSERT(elemsize, sizeof(int16_t));
1190
1191 _INSERT(prop->u.doubleValue, sizeof(double));
1192 break;
1193 }
1194 case MediaAnalyticsItem::kTypeRate:
1195 {
1196 elemtype = kRate;
1197 _INSERT(elemtype, sizeof(int8_t));
1198 elemsize = 2 * sizeof(uint64_t);
1199 _INSERT(elemsize, sizeof(int16_t));
1200
1201 _INSERT(prop->u.rate.count, sizeof(uint64_t));
1202 _INSERT(prop->u.rate.duration, sizeof(uint64_t));
1203 break;
1204 }
1205 case MediaAnalyticsItem::kTypeCString:
1206 {
1207 elemtype = kCString;
1208 _INSERT(elemtype, sizeof(int8_t));
1209 elemsize = strlen(prop->u.CStringValue) + 1;
1210 _INSERT(elemsize, sizeof(int16_t));
1211
1212 _INSERTSTRING(prop->u.CStringValue, elemsize);
1213 break;
1214 }
1215 default:
1216 // error if can't encode; warning if can't decode
1217 ALOGE("found bad Prop type: %d, idx %d, name %s",
1218 prop->mType, i, prop->mName);
1219 goto badness;
1220 }
1221 }
1222
1223 if (build + goal != filling) {
1224 ALOGE("problems populating; wrote=%d planned=%d",
1225 (int)(filling-build), goal);
1226 goto badness;
1227 }
1228
1229 *pbuffer = build;
1230 *plength = goal;
1231
1232 return true;
1233
1234 badness:
1235 free(build);
1236 return false;
1237}
1238
Ray Essick3938dc62016-11-01 08:56:56 -07001239} // namespace android
1240