blob: b7856a6536e349fb7422abe6817a5d6e28e987b5 [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
Ray Essickfc0a4732019-08-26 11:04:28 -070067MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
68 MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
69 return item;
70}
71
72mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
73 mediametrics_handle_t handle = (mediametrics_handle_t) item;
74 return handle;
75}
76
Ray Essick3938dc62016-11-01 08:56:56 -070077// access functions for the class
78MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080079 : mPid(-1),
80 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070081 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070082 mSessionID(MediaAnalyticsItem::SessionIDNone),
83 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080084 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080085 mPropCount(0), mPropSize(0), mProps(NULL)
86{
Ray Essick3938dc62016-11-01 08:56:56 -070087 mKey = MediaAnalyticsItem::kKeyNone;
88}
89
90MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080091 : mPid(-1),
92 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070093 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070094 mSessionID(MediaAnalyticsItem::SessionIDNone),
95 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080096 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080097 mPropCount(0), mPropSize(0), mProps(NULL)
98{
99 if (DEBUG_ALLOCATIONS) {
100 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
101 }
Ray Essick3938dc62016-11-01 08:56:56 -0700102 mKey = key;
103}
104
105MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800106 if (DEBUG_ALLOCATIONS) {
107 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
108 }
Ray Essick3938dc62016-11-01 08:56:56 -0700109 clear();
110}
111
Ray Essickb5fac8e2016-12-12 11:33:56 -0800112void MediaAnalyticsItem::clear() {
113
114 // clean allocated storage from key
115 mKey.clear();
116
Ray Essickd38e1742017-01-23 15:17:06 -0800117 // clean various major parameters
118 mSessionID = MediaAnalyticsItem::SessionIDNone;
119
Ray Essickb5fac8e2016-12-12 11:33:56 -0800120 // clean attributes
121 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700122 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800123 clearProp(&mProps[i]);
124 }
125 // the attribute records themselves
126 if (mProps != NULL) {
127 free(mProps);
128 mProps = NULL;
129 }
130 mPropSize = 0;
131 mPropCount = 0;
132
133 return;
134}
135
136// make a deep copy of myself
137MediaAnalyticsItem *MediaAnalyticsItem::dup() {
138 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
139
140 if (dst != NULL) {
141 // key as part of constructor
142 dst->mPid = this->mPid;
143 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700144 dst->mPkgName = this->mPkgName;
145 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800146 dst->mSessionID = this->mSessionID;
147 dst->mTimestamp = this->mTimestamp;
148 dst->mFinalized = this->mFinalized;
149
150 // properties aka attributes
151 dst->growProps(this->mPropCount);
152 for(size_t i=0;i<mPropCount;i++) {
153 copyProp(&dst->mProps[i], &this->mProps[i]);
154 }
155 dst->mPropCount = this->mPropCount;
156 }
157
158 return dst;
159}
160
Ray Essick3938dc62016-11-01 08:56:56 -0700161MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
162 mSessionID = id;
163 return *this;
164}
165
166MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
167 return mSessionID;
168}
169
170MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700171
172 if (mSessionID == SessionIDNone) {
173 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800174 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700175 sp<IMediaAnalyticsService> svc = getInstance();
176 if (svc != NULL) {
177 newid = svc->generateUniqueSessionID();
178 }
179 mSessionID = newid;
180 }
181
182 return mSessionID;
183}
184
185MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
186 mSessionID = MediaAnalyticsItem::SessionIDNone;
187 return *this;
188}
189
190MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
191 mTimestamp = ts;
192 return *this;
193}
194
195nsecs_t MediaAnalyticsItem::getTimestamp() const {
196 return mTimestamp;
197}
198
199MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
200 mPid = pid;
201 return *this;
202}
203
204pid_t MediaAnalyticsItem::getPid() const {
205 return mPid;
206}
207
208MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
209 mUid = uid;
210 return *this;
211}
212
213uid_t MediaAnalyticsItem::getUid() const {
214 return mUid;
215}
216
Ray Essick783bd0d2018-01-11 11:10:35 -0800217MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700218 mPkgName = pkgName;
219 return *this;
220}
221
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800222MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700223 mPkgVersionCode = pkgVersionCode;
224 return *this;
225}
226
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800227int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700228 return mPkgVersionCode;
229}
230
Ray Essickb5fac8e2016-12-12 11:33:56 -0800231// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700232MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700233 mKey = key;
234 return *this;
235}
236
237MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
238 return mKey;
239}
240
Ray Essickb5fac8e2016-12-12 11:33:56 -0800241// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700242int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800243 return mPropCount;
244}
245
246// find the proper entry in the list
247size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
248{
249 size_t i = 0;
250 for (; i < mPropCount; i++) {
251 Prop *prop = &mProps[i];
252 if (prop->mNameLen != len) {
253 continue;
254 }
255 if (memcmp(name, prop->mName, len) == 0) {
256 break;
257 }
258 }
259 return i;
260}
261
262MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
263 size_t len = strlen(name);
264 size_t i = findPropIndex(name, len);
265 if (i < mPropCount) {
266 return &mProps[i];
267 }
268 return NULL;
269}
270
271void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700272 free((void *)mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800273 mName = (const char *) malloc(len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700274 LOG_ALWAYS_FATAL_IF(mName == NULL,
275 "failed malloc() for property '%s' (len %zu)",
276 name, len);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800277 memcpy ((void *)mName, name, len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700278 mNameLen = len;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800279}
280
Ray Essick9ce18f72018-05-07 15:54:30 -0700281// consider this "find-or-allocate".
282// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800283MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
284 size_t len = strlen(name);
285 size_t i = findPropIndex(name, len);
286 Prop *prop;
287
288 if (i < mPropCount) {
289 prop = &mProps[i];
290 } else {
291 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700292 if (growProps() == false) {
293 ALOGE("failed allocation for new props");
294 return NULL;
295 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800296 }
297 i = mPropCount++;
298 prop = &mProps[i];
299 prop->setName(name, len);
300 }
301
302 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700303}
304
Ray Essickf65f4212017-08-31 11:41:19 -0700305// used within the summarizers; return whether property existed
306bool MediaAnalyticsItem::removeProp(const char *name) {
307 size_t len = strlen(name);
308 size_t i = findPropIndex(name, len);
309 if (i < mPropCount) {
310 Prop *prop = &mProps[i];
311 clearProp(prop);
312 if (i != mPropCount-1) {
313 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700314 copyProp(prop, &mProps[mPropCount-1]);
315 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700316 }
317 mPropCount--;
318 return true;
319 }
320 return false;
321}
322
Ray Essick3938dc62016-11-01 08:56:56 -0700323// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800324void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
325 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700326 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700327 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700328 prop->mType = kTypeInt32;
329 prop->u.int32Value = value;
330 }
Ray Essick3938dc62016-11-01 08:56:56 -0700331}
332
Ray Essickb5fac8e2016-12-12 11:33:56 -0800333void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
334 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700335 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700336 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700337 prop->mType = kTypeInt64;
338 prop->u.int64Value = value;
339 }
Ray Essick3938dc62016-11-01 08:56:56 -0700340}
341
Ray Essickb5fac8e2016-12-12 11:33:56 -0800342void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
343 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700344 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700345 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700346 prop->mType = kTypeDouble;
347 prop->u.doubleValue = value;
348 }
Ray Essick3938dc62016-11-01 08:56:56 -0700349}
350
Ray Essickb5fac8e2016-12-12 11:33:56 -0800351void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
352
353 Prop *prop = allocateProp(name);
354 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700355 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700356 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700357 prop->mType = kTypeCString;
358 prop->u.CStringValue = strdup(value);
359 }
Ray Essick3938dc62016-11-01 08:56:56 -0700360}
361
Ray Essickb5fac8e2016-12-12 11:33:56 -0800362void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
363 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700364 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700365 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700366 prop->mType = kTypeRate;
367 prop->u.rate.count = count;
368 prop->u.rate.duration = duration;
369 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800370}
371
372
Ray Essick3938dc62016-11-01 08:56:56 -0700373// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800374void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
375 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700376 if (prop == NULL) {
377 return;
378 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800379 switch (prop->mType) {
380 case kTypeInt32:
381 prop->u.int32Value += value;
382 break;
383 default:
384 clearPropValue(prop);
385 prop->mType = kTypeInt32;
386 prop->u.int32Value = value;
387 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700388 }
Ray Essick3938dc62016-11-01 08:56:56 -0700389}
390
Ray Essickb5fac8e2016-12-12 11:33:56 -0800391void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
392 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700393 if (prop == NULL) {
394 return;
395 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800396 switch (prop->mType) {
397 case kTypeInt64:
398 prop->u.int64Value += value;
399 break;
400 default:
401 clearPropValue(prop);
402 prop->mType = kTypeInt64;
403 prop->u.int64Value = value;
404 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700405 }
Ray Essick3938dc62016-11-01 08:56:56 -0700406}
407
Ray Essickb5fac8e2016-12-12 11:33:56 -0800408void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
409 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700410 if (prop == NULL) {
411 return;
412 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800413 switch (prop->mType) {
414 case kTypeRate:
415 prop->u.rate.count += count;
416 prop->u.rate.duration += duration;
417 break;
418 default:
419 clearPropValue(prop);
420 prop->mType = kTypeRate;
421 prop->u.rate.count = count;
422 prop->u.rate.duration = duration;
423 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700424 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800425}
426
427void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
428 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700429 if (prop == NULL) {
430 return;
431 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800432 switch (prop->mType) {
433 case kTypeDouble:
434 prop->u.doubleValue += value;
435 break;
436 default:
437 clearPropValue(prop);
438 prop->mType = kTypeDouble;
439 prop->u.doubleValue = value;
440 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700441 }
Ray Essick3938dc62016-11-01 08:56:56 -0700442}
443
444// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800445bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
446 Prop *prop = findProp(name);
447 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700448 return false;
449 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800450 if (value != NULL) {
451 *value = prop->u.int32Value;
452 }
Ray Essick3938dc62016-11-01 08:56:56 -0700453 return true;
454}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800455
456bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
457 Prop *prop = findProp(name);
458 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700459 return false;
460 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800461 if (value != NULL) {
462 *value = prop->u.int64Value;
463 }
Ray Essick3938dc62016-11-01 08:56:56 -0700464 return true;
465}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800466
467bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
468 Prop *prop = findProp(name);
469 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700470 return false;
471 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800472 if (count != NULL) {
473 *count = prop->u.rate.count;
474 }
475 if (duration != NULL) {
476 *duration = prop->u.rate.duration;
477 }
478 if (rate != NULL) {
479 double r = 0.0;
480 if (prop->u.rate.duration != 0) {
481 r = prop->u.rate.count / (double) prop->u.rate.duration;
482 }
483 *rate = r;
484 }
485 return true;
486}
487
488bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
489 Prop *prop = findProp(name);
490 if (prop == NULL || prop->mType != kTypeDouble) {
491 return false;
492 }
493 if (value != NULL) {
494 *value = prop->u.doubleValue;
495 }
Ray Essick3938dc62016-11-01 08:56:56 -0700496 return true;
497}
498
499// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800500bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
501 Prop *prop = findProp(name);
Ray Essick9db7b812018-11-15 12:42:19 -0800502 if (prop == NULL || prop->mType != kTypeCString) {
Ray Essick3938dc62016-11-01 08:56:56 -0700503 return false;
504 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800505 if (value != NULL) {
506 *value = strdup(prop->u.CStringValue);
507 }
Ray Essick3938dc62016-11-01 08:56:56 -0700508 return true;
509}
510
Ray Essick20147322018-11-17 09:08:39 -0800511bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
512 Prop *prop = findProp(name);
513 if (prop == NULL || prop->mType != kTypeCString) {
514 return false;
515 }
516 if (value != NULL) {
517 // std::string makes a copy for us
518 *value = prop->u.CStringValue;
519 }
520 return true;
521}
522
Ray Essick3938dc62016-11-01 08:56:56 -0700523// remove indicated keys and their values
524// return value is # keys removed
525int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
526 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800527 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700528 return -1;
529 }
530 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800531 const char *name = attrs[i];
532 size_t len = strlen(name);
533 size_t j = findPropIndex(name, len);
534 if (j >= mPropCount) {
535 // not there
536 continue;
537 } else if (j+1 == mPropCount) {
538 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700539 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800540 clearProp(&mProps[j]);
541 mPropCount--;
542 } else {
543 // in the middle, bring last one down and shorten
544 zapped++;
545 clearProp(&mProps[j]);
546 mProps[j] = mProps[mPropCount-1];
547 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700548 }
549 }
550 return zapped;
551}
552
553// remove any keys NOT in the provided list
554// return value is # keys removed
555int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
556 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800557 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700558 return -1;
559 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800560 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
561 Prop *prop = &mProps[i];
562 for (ssize_t j = 0; j < n ; j++) {
563 if (strcmp(prop->mName, attrs[j]) == 0) {
564 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700565 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800566 if (i != (ssize_t)(mPropCount-1)) {
567 *prop = mProps[mPropCount-1];
568 }
569 initProp(&mProps[mPropCount-1]);
570 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700571 break;
572 }
573 }
574 }
575 return zapped;
576}
577
578// remove a single key
579// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800580int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
581 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700582}
583
Ray Essick3938dc62016-11-01 08:56:56 -0700584// handle individual items/properties stored within the class
585//
Ray Essick3938dc62016-11-01 08:56:56 -0700586
Ray Essickb5fac8e2016-12-12 11:33:56 -0800587void MediaAnalyticsItem::initProp(Prop *prop) {
588 if (prop != NULL) {
589 prop->mName = NULL;
590 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700591
Ray Essickb5fac8e2016-12-12 11:33:56 -0800592 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700593 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800594}
595
596void MediaAnalyticsItem::clearProp(Prop *prop)
597{
598 if (prop != NULL) {
599 if (prop->mName != NULL) {
600 free((void *)prop->mName);
601 prop->mName = NULL;
602 prop->mNameLen = 0;
603 }
604
605 clearPropValue(prop);
606 }
607}
608
609void MediaAnalyticsItem::clearPropValue(Prop *prop)
610{
611 if (prop != NULL) {
612 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
613 free(prop->u.CStringValue);
614 prop->u.CStringValue = NULL;
615 }
616 prop->mType = kTypeNone;
617 }
618}
619
620void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
621{
622 // get rid of any pointers in the dst
623 clearProp(dst);
624
625 *dst = *src;
626
627 // fix any pointers that we blindly copied, so we have our own copies
628 if (dst->mName) {
629 void *p = malloc(dst->mNameLen + 1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700630 LOG_ALWAYS_FATAL_IF(p == NULL,
631 "failed malloc() duping property '%s' (len %zu)",
632 dst->mName, dst->mNameLen);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800633 memcpy (p, src->mName, dst->mNameLen + 1);
634 dst->mName = (const char *) p;
635 }
636 if (dst->mType == kTypeCString) {
637 dst->u.CStringValue = strdup(src->u.CStringValue);
638 }
639}
640
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700641bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800642{
643 if (increment <= 0) {
644 increment = kGrowProps;
645 }
646 int nsize = mPropSize + increment;
647 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
648
649 if (ni != NULL) {
650 for (int i = mPropSize; i < nsize; i++) {
651 initProp(&ni[i]);
652 }
653 mProps = ni;
654 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700655 return true;
656 } else {
657 ALOGW("MediaAnalyticsItem::growProps fails");
658 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800659 }
Ray Essick3938dc62016-11-01 08:56:56 -0700660}
661
662// Parcel / serialize things for binder calls
663//
664
665int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800666 int32_t version = data.readInt32();
667
668 switch(version) {
669 case 0:
670 return readFromParcel0(data);
671 break;
672 default:
673 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
674 return -1;
675 }
676}
677
678int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700679 // into 'this' object
680 // .. we make a copy of the string to put away.
681 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700682 mPid = data.readInt32();
683 mUid = data.readInt32();
684 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800685 mPkgVersionCode = data.readInt64();
Ray Essick3938dc62016-11-01 08:56:56 -0700686 mSessionID = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800687 // We no longer pay attention to user setting of finalized, BUT it's
688 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700689 mFinalized = data.readInt32();
Ray Essick92d23b42018-01-29 12:10:30 -0800690 mFinalized = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700691 mTimestamp = data.readInt64();
692
693 int count = data.readInt32();
694 for (int i = 0; i < count ; i++) {
695 MediaAnalyticsItem::Attr attr = data.readCString();
696 int32_t ztype = data.readInt32();
697 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800698 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700699 setInt32(attr, data.readInt32());
700 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800701 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700702 setInt64(attr, data.readInt64());
703 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800704 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700705 setDouble(attr, data.readDouble());
706 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800707 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700708 setCString(attr, data.readCString());
709 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800710 case MediaAnalyticsItem::kTypeRate:
711 {
712 int64_t count = data.readInt64();
713 int64_t duration = data.readInt64();
714 setRate(attr, count, duration);
715 }
716 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700717 default:
718 ALOGE("reading bad item type: %d, idx %d",
719 ztype, i);
720 return -1;
721 }
722 }
723
724 return 0;
725}
726
727int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800728
Ray Essick3938dc62016-11-01 08:56:56 -0700729 if (data == NULL) return -1;
730
Ray Essickba8c4842019-01-18 11:35:33 -0800731 int32_t version = 0;
732 data->writeInt32(version);
733
734 switch(version) {
735 case 0:
736 return writeToParcel0(data);
737 break;
738 default:
739 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
740 return -1;
741 }
742}
743
744int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700745
746 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700747 data->writeInt32(mPid);
748 data->writeInt32(mUid);
749 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800750 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700751 data->writeInt64(mSessionID);
752 data->writeInt32(mFinalized);
753 data->writeInt64(mTimestamp);
754
755 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800756 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700757 data->writeInt32(count);
758 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800759 Prop *prop = &mProps[i];
760 data->writeCString(prop->mName);
761 data->writeInt32(prop->mType);
762 switch (prop->mType) {
763 case MediaAnalyticsItem::kTypeInt32:
764 data->writeInt32(prop->u.int32Value);
765 break;
766 case MediaAnalyticsItem::kTypeInt64:
767 data->writeInt64(prop->u.int64Value);
768 break;
769 case MediaAnalyticsItem::kTypeDouble:
770 data->writeDouble(prop->u.doubleValue);
771 break;
772 case MediaAnalyticsItem::kTypeRate:
773 data->writeInt64(prop->u.rate.count);
774 data->writeInt64(prop->u.rate.duration);
775 break;
776 case MediaAnalyticsItem::kTypeCString:
777 data->writeCString(prop->u.CStringValue);
778 break;
779 default:
780 ALOGE("found bad Prop type: %d, idx %d, name %s",
781 prop->mType, i, prop->mName);
782 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700783 }
784 }
785
786 return 0;
787}
788
Ray Essick20147322018-11-17 09:08:39 -0800789const char *MediaAnalyticsItem::toCString() {
790 return toCString(PROTO_LAST);
791}
792
793const char * MediaAnalyticsItem::toCString(int version) {
794 std::string val = toString(version);
795 return strdup(val.c_str());
796}
797
Ray Essick783bd0d2018-01-11 11:10:35 -0800798std::string MediaAnalyticsItem::toString() {
Ray Essick5b77bd22018-01-23 16:11:06 -0800799 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700800}
Ray Essick3938dc62016-11-01 08:56:56 -0700801
Ray Essick783bd0d2018-01-11 11:10:35 -0800802std::string MediaAnalyticsItem::toString(int version) {
Ray Essickf65f4212017-08-31 11:41:19 -0700803
804 // v0 : released with 'o'
805 // v1 : bug fix (missing pid/finalized separator),
806 // adds apk name, apk version code
807
808 if (version <= PROTO_FIRST) {
809 // default to original v0 format, until proper parsers are in place
810 version = PROTO_V0;
811 } else if (version > PROTO_LAST) {
812 version = PROTO_LAST;
813 }
814
Ray Essick783bd0d2018-01-11 11:10:35 -0800815 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800816 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700817
Ray Essickf65f4212017-08-31 11:41:19 -0700818 if (version == PROTO_V0) {
819 result = "(";
820 } else {
821 snprintf(buffer, sizeof(buffer), "[%d:", version);
822 result.append(buffer);
823 }
824
Ray Essick3938dc62016-11-01 08:56:56 -0700825 // same order as we spill into the parcel, although not required
826 // key+session are our primary matching criteria
827 result.append(mKey.c_str());
828 result.append(":");
829 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
830 result.append(buffer);
831
Ray Essickf65f4212017-08-31 11:41:19 -0700832 snprintf(buffer, sizeof(buffer), "%d:", mUid);
833 result.append(buffer);
834
835 if (version >= PROTO_V1) {
836 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800837 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700838 result.append(buffer);
839 }
840
841 // in 'o' (v1) , the separator between pid and finalized was omitted
842 if (version <= PROTO_V0) {
843 snprintf(buffer, sizeof(buffer), "%d", mPid);
844 } else {
845 snprintf(buffer, sizeof(buffer), "%d:", mPid);
846 }
Ray Essick3938dc62016-11-01 08:56:56 -0700847 result.append(buffer);
848
849 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
850 result.append(buffer);
851 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
852 result.append(buffer);
853
854 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800855 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700856 snprintf(buffer, sizeof(buffer), "%d:", count);
857 result.append(buffer);
858 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800859 Prop *prop = &mProps[i];
860 switch (prop->mType) {
861 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700862 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800863 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700864 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800865 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700866 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800867 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700868 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800869 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700870 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800871 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700872 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800873 case MediaAnalyticsItem::kTypeRate:
874 snprintf(buffer,sizeof(buffer),
875 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
876 prop->u.rate.count, prop->u.rate.duration);
877 break;
878 case MediaAnalyticsItem::kTypeCString:
879 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700880 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800881 // XXX: sanitize string for ':' '='
882 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700883 buffer[0] = ':';
884 buffer[1] = '\0';
885 break;
886 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800887 ALOGE("to_String bad item type: %d for %s",
888 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700889 break;
890 }
891 result.append(buffer);
892 }
893
Ray Essickf65f4212017-08-31 11:41:19 -0700894 if (version == PROTO_V0) {
895 result.append(")");
896 } else {
897 result.append("]");
898 }
Ray Essick3938dc62016-11-01 08:56:56 -0700899
900 return result;
901}
902
903// for the lazy, we offer methods that finds the service and
904// calls the appropriate daemon
905bool MediaAnalyticsItem::selfrecord() {
906 return selfrecord(false);
907}
908
909bool MediaAnalyticsItem::selfrecord(bool forcenew) {
910
Ray Essickb5fac8e2016-12-12 11:33:56 -0800911 if (DEBUG_API) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800912 std::string p = this->toString();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800913 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
914 }
Ray Essick3938dc62016-11-01 08:56:56 -0700915
916 sp<IMediaAnalyticsService> svc = getInstance();
917
918 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700919 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
920 if (newid == SessionIDInvalid) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800921 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700922 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
923 return false;
924 }
Ray Essick3938dc62016-11-01 08:56:56 -0700925 return true;
926 } else {
927 return false;
928 }
929}
930
931// get a connection we can reuse for most of our lifetime
932// static
933sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
934static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700935static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700936
937//static
938bool MediaAnalyticsItem::isEnabled() {
939 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
940
941 if (enabled == -1) {
942 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
943 }
944 if (enabled == -1) {
945 enabled = MediaAnalyticsItem::EnabledProperty_default;
946 }
947 if (enabled <= 0) {
948 return false;
949 }
950 return true;
951}
952
Ray Essick2ab3c432017-10-02 09:29:49 -0700953
954// monitor health of our connection to the metrics service
955class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
956 virtual void binderDied(const wp<IBinder> &) {
957 ALOGW("Reacquire service connection on next request");
958 MediaAnalyticsItem::dropInstance();
959 }
960};
961
962static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
963
964// static
965void MediaAnalyticsItem::dropInstance() {
966 Mutex::Autolock _l(sInitMutex);
967 remainingBindAttempts = SVC_TRIES;
968 sAnalyticsService = NULL;
969}
970
Ray Essick3938dc62016-11-01 08:56:56 -0700971//static
972sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700973
Ray Essickd38e1742017-01-23 15:17:06 -0800974 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700975 int enabled = isEnabled();
976
977 if (enabled == false) {
978 if (DEBUG_SERVICEACCESS) {
979 ALOGD("disabled");
980 }
981 return NULL;
982 }
983
Ray Essick79a89ef2017-04-24 15:52:54 -0700984 // completely skip logging from certain UIDs. We do this here
985 // to avoid the multi-second timeouts while we learn that
986 // sepolicy will not let us find the service.
987 // We do this only for a select set of UIDs
988 // The sepolicy protection is still in place, we just want a faster
989 // response from this specific, small set of uids.
990 {
991 uid_t uid = getuid();
992 switch (uid) {
993 case AID_RADIO: // telephony subsystem, RIL
994 return NULL;
995 break;
996 default:
997 // let sepolicy deny access if appropriate
998 break;
999 }
1000 }
1001
Ray Essick3938dc62016-11-01 08:56:56 -07001002 {
1003 Mutex::Autolock _l(sInitMutex);
1004 const char *badness = "";
1005
Ray Essick2ab3c432017-10-02 09:29:49 -07001006 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -08001007 // (1) we haven't tried to initialize it yet
1008 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -07001009 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -07001010 sp<IServiceManager> sm = defaultServiceManager();
1011 if (sm != NULL) {
1012 sp<IBinder> binder = sm->getService(String16(servicename));
1013 if (binder != NULL) {
1014 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -07001015 if (sNotifier != NULL) {
1016 sNotifier = NULL;
1017 }
1018 sNotifier = new MediaMetricsDeathNotifier();
1019 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -07001020 } else {
1021 badness = "did not find service";
1022 }
1023 } else {
1024 badness = "No Service Manager access";
1025 }
Ray Essickb5fac8e2016-12-12 11:33:56 -08001026
1027 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -07001028 if (remainingBindAttempts > 0) {
1029 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -08001030 }
1031 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -07001032 ALOGD("Unable to bind to service %s: %s", servicename, badness);
1033 }
1034 }
1035 }
Ray Essickb5fac8e2016-12-12 11:33:56 -08001036
Ray Essick3938dc62016-11-01 08:56:56 -07001037 return sAnalyticsService;
1038 }
1039}
1040
Ray Essick3938dc62016-11-01 08:56:56 -07001041// merge the info from 'incoming' into this record.
1042// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -08001043bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -07001044
1045 // if I don't have key or session id, take them from incoming
1046 // 'this' should never be missing both of them...
1047 if (mKey.empty()) {
1048 mKey = incoming->mKey;
1049 } else if (mSessionID == 0) {
1050 mSessionID = incoming->mSessionID;
1051 }
1052
Ray Essick3938dc62016-11-01 08:56:56 -07001053 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -08001054 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -07001055 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -08001056 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -08001057 const char *p = iprop->mName;
1058 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001059
1060 // should ignore a zero length name...
1061 if (len == 0) {
1062 continue;
1063 }
1064
1065 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -07001066
Ray Essickb5fac8e2016-12-12 11:33:56 -08001067 if (oprop == NULL) {
1068 // no oprop, so we insert the new one
1069 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001070 if (oprop != NULL) {
1071 copyProp(oprop, iprop);
1072 } else {
1073 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -08001074 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001075 } else {
1076 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -07001077 }
1078 }
1079
1080 // not sure when we'd return false...
1081 return true;
1082}
1083
Ray Essickba8c4842019-01-18 11:35:33 -08001084// a byte array; contents are
1085// overall length (uint32) including the length field itself
1086// encoding version (uint32)
1087// count of properties (uint32)
1088// N copies of:
1089// property name as length(int16), bytes
1090// the bytes WILL include the null terminator of the name
1091// type (uint8 -- 1 byte)
1092// size of value field (int16 -- 2 bytes)
1093// value (size based on type)
1094// int32, int64, double -- little endian 4/8/8 bytes respectively
1095// cstring -- N bytes of value [WITH terminator]
1096
1097enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
1098
1099bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
1100
1101 char *build = NULL;
1102
1103 if (pbuffer == NULL || plength == NULL)
1104 return false;
1105
1106 // consistency for the caller, who owns whatever comes back in this pointer.
1107 *pbuffer = NULL;
1108
1109 // first, let's calculate sizes
1110 int32_t goal = 0;
1111 int32_t version = 0;
1112
1113 goal += sizeof(uint32_t); // overall length, including the length field
1114 goal += sizeof(uint32_t); // encoding version
1115 goal += sizeof(uint32_t); // # properties
1116
1117 int32_t count = mPropCount;
1118 for (int i = 0 ; i < count; i++ ) {
1119 Prop *prop = &mProps[i];
1120 goal += sizeof(uint16_t); // name length
1121 goal += strlen(prop->mName) + 1; // string + null
1122 goal += sizeof(uint8_t); // type
1123 goal += sizeof(uint16_t); // size of value
1124 switch (prop->mType) {
1125 case MediaAnalyticsItem::kTypeInt32:
1126 goal += sizeof(uint32_t);
1127 break;
1128 case MediaAnalyticsItem::kTypeInt64:
1129 goal += sizeof(uint64_t);
1130 break;
1131 case MediaAnalyticsItem::kTypeDouble:
1132 goal += sizeof(double);
1133 break;
1134 case MediaAnalyticsItem::kTypeRate:
1135 goal += 2 * sizeof(uint64_t);
1136 break;
1137 case MediaAnalyticsItem::kTypeCString:
1138 // length + actual string + null
1139 goal += strlen(prop->u.CStringValue) + 1;
1140 break;
1141 default:
1142 ALOGE("found bad Prop type: %d, idx %d, name %s",
1143 prop->mType, i, prop->mName);
1144 return false;
1145 }
1146 }
1147
1148 // now that we have a size... let's allocate and fill
1149 build = (char *)malloc(goal);
1150 if (build == NULL)
1151 return false;
1152
1153 memset(build, 0, goal);
1154
1155 char *filling = build;
1156
1157#define _INSERT(val, size) \
1158 { memcpy(filling, &(val), (size)); filling += (size);}
1159#define _INSERTSTRING(val, size) \
1160 { memcpy(filling, (val), (size)); filling += (size);}
1161
1162 _INSERT(goal, sizeof(int32_t));
1163 _INSERT(version, sizeof(int32_t));
1164 _INSERT(count, sizeof(int32_t));
1165
1166 for (int i = 0 ; i < count; i++ ) {
1167 Prop *prop = &mProps[i];
1168 int16_t attrNameLen = strlen(prop->mName) + 1;
1169 _INSERT(attrNameLen, sizeof(int16_t));
1170 _INSERTSTRING(prop->mName, attrNameLen); // termination included
1171 int8_t elemtype;
1172 int16_t elemsize;
1173 switch (prop->mType) {
1174 case MediaAnalyticsItem::kTypeInt32:
1175 {
1176 elemtype = kInt32;
1177 _INSERT(elemtype, sizeof(int8_t));
1178 elemsize = sizeof(int32_t);
1179 _INSERT(elemsize, sizeof(int16_t));
1180
1181 _INSERT(prop->u.int32Value, sizeof(int32_t));
1182 break;
1183 }
1184 case MediaAnalyticsItem::kTypeInt64:
1185 {
1186 elemtype = kInt64;
1187 _INSERT(elemtype, sizeof(int8_t));
1188 elemsize = sizeof(int64_t);
1189 _INSERT(elemsize, sizeof(int16_t));
1190
1191 _INSERT(prop->u.int64Value, sizeof(int64_t));
1192 break;
1193 }
1194 case MediaAnalyticsItem::kTypeDouble:
1195 {
1196 elemtype = kDouble;
1197 _INSERT(elemtype, sizeof(int8_t));
1198 elemsize = sizeof(double);
1199 _INSERT(elemsize, sizeof(int16_t));
1200
1201 _INSERT(prop->u.doubleValue, sizeof(double));
1202 break;
1203 }
1204 case MediaAnalyticsItem::kTypeRate:
1205 {
1206 elemtype = kRate;
1207 _INSERT(elemtype, sizeof(int8_t));
1208 elemsize = 2 * sizeof(uint64_t);
1209 _INSERT(elemsize, sizeof(int16_t));
1210
1211 _INSERT(prop->u.rate.count, sizeof(uint64_t));
1212 _INSERT(prop->u.rate.duration, sizeof(uint64_t));
1213 break;
1214 }
1215 case MediaAnalyticsItem::kTypeCString:
1216 {
1217 elemtype = kCString;
1218 _INSERT(elemtype, sizeof(int8_t));
1219 elemsize = strlen(prop->u.CStringValue) + 1;
1220 _INSERT(elemsize, sizeof(int16_t));
1221
1222 _INSERTSTRING(prop->u.CStringValue, elemsize);
1223 break;
1224 }
1225 default:
1226 // error if can't encode; warning if can't decode
1227 ALOGE("found bad Prop type: %d, idx %d, name %s",
1228 prop->mType, i, prop->mName);
1229 goto badness;
1230 }
1231 }
1232
1233 if (build + goal != filling) {
1234 ALOGE("problems populating; wrote=%d planned=%d",
1235 (int)(filling-build), goal);
1236 goto badness;
1237 }
1238
1239 *pbuffer = build;
1240 *plength = goal;
1241
1242 return true;
1243
1244 badness:
1245 free(build);
1246 return false;
1247}
1248
Ray Essick3938dc62016-11-01 08:56:56 -07001249} // namespace android
1250