blob: 47a147ecaa6f4a99712ae44c70019c72ba84d1b0 [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
32#include <media/stagefright/foundation/AString.h>
33
34#include <binder/IServiceManager.h>
35#include <media/IMediaAnalyticsService.h>
36#include <media/MediaAnalyticsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070037#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070038
39namespace android {
40
41#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080042#define DEBUG_API 0
43#define DEBUG_ALLOCATIONS 0
44
45// after this many failed attempts, we stop trying [from this process] and just say that
46// the service is off.
47#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070048
49// the few universal keys we have
50const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
51const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
52
Ray Essickd38e1742017-01-23 15:17:06 -080053const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
54const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
Ray Essickd6a6c672017-01-25 14:28:51 -080055const int MediaAnalyticsItem::EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -070056
57
58// access functions for the class
59MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080060 : mPid(-1),
61 mUid(-1),
Ray Essick3938dc62016-11-01 08:56:56 -070062 mSessionID(MediaAnalyticsItem::SessionIDNone),
63 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080064 mFinalized(0),
65 mPropCount(0), mPropSize(0), mProps(NULL)
66{
Ray Essick3938dc62016-11-01 08:56:56 -070067 mKey = MediaAnalyticsItem::kKeyNone;
68}
69
70MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080071 : mPid(-1),
72 mUid(-1),
Ray Essick3938dc62016-11-01 08:56:56 -070073 mSessionID(MediaAnalyticsItem::SessionIDNone),
74 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080075 mFinalized(0),
76 mPropCount(0), mPropSize(0), mProps(NULL)
77{
78 if (DEBUG_ALLOCATIONS) {
79 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
80 }
Ray Essick3938dc62016-11-01 08:56:56 -070081 mKey = key;
82}
83
84MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080085 if (DEBUG_ALLOCATIONS) {
86 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
87 }
Ray Essick3938dc62016-11-01 08:56:56 -070088 clear();
89}
90
Ray Essickb5fac8e2016-12-12 11:33:56 -080091void MediaAnalyticsItem::clear() {
92
93 // clean allocated storage from key
94 mKey.clear();
95
Ray Essickd38e1742017-01-23 15:17:06 -080096 // clean various major parameters
97 mSessionID = MediaAnalyticsItem::SessionIDNone;
98
Ray Essickb5fac8e2016-12-12 11:33:56 -080099 // clean attributes
100 // contents of the attributes
101 for (size_t i = 0 ; i < mPropSize; i++ ) {
102 clearProp(&mProps[i]);
103 }
104 // the attribute records themselves
105 if (mProps != NULL) {
106 free(mProps);
107 mProps = NULL;
108 }
109 mPropSize = 0;
110 mPropCount = 0;
111
112 return;
113}
114
115// make a deep copy of myself
116MediaAnalyticsItem *MediaAnalyticsItem::dup() {
117 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
118
119 if (dst != NULL) {
120 // key as part of constructor
121 dst->mPid = this->mPid;
122 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700123 dst->mPkgName = this->mPkgName;
124 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800125 dst->mSessionID = this->mSessionID;
126 dst->mTimestamp = this->mTimestamp;
127 dst->mFinalized = this->mFinalized;
128
129 // properties aka attributes
130 dst->growProps(this->mPropCount);
131 for(size_t i=0;i<mPropCount;i++) {
132 copyProp(&dst->mProps[i], &this->mProps[i]);
133 }
134 dst->mPropCount = this->mPropCount;
135 }
136
137 return dst;
138}
139
Ray Essick3938dc62016-11-01 08:56:56 -0700140// so clients can send intermediate values to be overlaid later
141MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
142 mFinalized = value;
143 return *this;
144}
145
146bool MediaAnalyticsItem::getFinalized() const {
147 return mFinalized;
148}
149
150MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
151 mSessionID = id;
152 return *this;
153}
154
155MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
156 return mSessionID;
157}
158
159MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700160
161 if (mSessionID == SessionIDNone) {
162 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800163 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700164 sp<IMediaAnalyticsService> svc = getInstance();
165 if (svc != NULL) {
166 newid = svc->generateUniqueSessionID();
167 }
168 mSessionID = newid;
169 }
170
171 return mSessionID;
172}
173
174MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
175 mSessionID = MediaAnalyticsItem::SessionIDNone;
176 return *this;
177}
178
179MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
180 mTimestamp = ts;
181 return *this;
182}
183
184nsecs_t MediaAnalyticsItem::getTimestamp() const {
185 return mTimestamp;
186}
187
188MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
189 mPid = pid;
190 return *this;
191}
192
193pid_t MediaAnalyticsItem::getPid() const {
194 return mPid;
195}
196
197MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
198 mUid = uid;
199 return *this;
200}
201
202uid_t MediaAnalyticsItem::getUid() const {
203 return mUid;
204}
205
Ray Essickf65f4212017-08-31 11:41:19 -0700206MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
207 mPkgName = pkgName;
208 return *this;
209}
210
211AString MediaAnalyticsItem::getPkgName() const {
212 return mPkgName;
213}
214
215MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int32_t pkgVersionCode) {
216 mPkgVersionCode = pkgVersionCode;
217 return *this;
218}
219
220int32_t MediaAnalyticsItem::getPkgVersionCode() const {
221 return mPkgVersionCode;
222}
223
Ray Essickb5fac8e2016-12-12 11:33:56 -0800224// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700225MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700226 mKey = key;
227 return *this;
228}
229
230MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
231 return mKey;
232}
233
Ray Essickb5fac8e2016-12-12 11:33:56 -0800234// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700235int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800236 return mPropCount;
237}
238
239// find the proper entry in the list
240size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
241{
242 size_t i = 0;
243 for (; i < mPropCount; i++) {
244 Prop *prop = &mProps[i];
245 if (prop->mNameLen != len) {
246 continue;
247 }
248 if (memcmp(name, prop->mName, len) == 0) {
249 break;
250 }
251 }
252 return i;
253}
254
255MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
256 size_t len = strlen(name);
257 size_t i = findPropIndex(name, len);
258 if (i < mPropCount) {
259 return &mProps[i];
260 }
261 return NULL;
262}
263
264void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
265 mNameLen = len;
266 mName = (const char *) malloc(len+1);
267 memcpy ((void *)mName, name, len+1);
268}
269
270// used only as part of a storing operation
271MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
272 size_t len = strlen(name);
273 size_t i = findPropIndex(name, len);
274 Prop *prop;
275
276 if (i < mPropCount) {
277 prop = &mProps[i];
278 } else {
279 if (i == mPropSize) {
280 growProps();
281 // XXX: verify success
282 }
283 i = mPropCount++;
284 prop = &mProps[i];
285 prop->setName(name, len);
Ray Essickf65f4212017-08-31 11:41:19 -0700286 prop->mType = kTypeNone; // make caller set type info
Ray Essickb5fac8e2016-12-12 11:33:56 -0800287 }
288
289 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700290}
291
Ray Essickf65f4212017-08-31 11:41:19 -0700292// used within the summarizers; return whether property existed
293bool MediaAnalyticsItem::removeProp(const char *name) {
294 size_t len = strlen(name);
295 size_t i = findPropIndex(name, len);
296 if (i < mPropCount) {
297 Prop *prop = &mProps[i];
298 clearProp(prop);
299 if (i != mPropCount-1) {
300 // in the middle, bring last one down to fill gap
301 mProps[i] = mProps[mPropCount-1];
302 }
303 mPropCount--;
304 return true;
305 }
306 return false;
307}
308
Ray Essick3938dc62016-11-01 08:56:56 -0700309// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800310void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
311 Prop *prop = allocateProp(name);
312 prop->mType = kTypeInt32;
313 prop->u.int32Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700314}
315
Ray Essickb5fac8e2016-12-12 11:33:56 -0800316void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
317 Prop *prop = allocateProp(name);
318 prop->mType = kTypeInt64;
319 prop->u.int64Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700320}
321
Ray Essickb5fac8e2016-12-12 11:33:56 -0800322void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
323 Prop *prop = allocateProp(name);
324 prop->mType = kTypeDouble;
325 prop->u.doubleValue = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700326}
327
Ray Essickb5fac8e2016-12-12 11:33:56 -0800328void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
329
330 Prop *prop = allocateProp(name);
331 // any old value will be gone
332 prop->mType = kTypeCString;
333 prop->u.CStringValue = strdup(value);
Ray Essick3938dc62016-11-01 08:56:56 -0700334}
335
Ray Essickb5fac8e2016-12-12 11:33:56 -0800336void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
337 Prop *prop = allocateProp(name);
338 prop->mType = kTypeRate;
339 prop->u.rate.count = count;
340 prop->u.rate.duration = duration;
341}
342
343
Ray Essick3938dc62016-11-01 08:56:56 -0700344// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800345void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
346 Prop *prop = allocateProp(name);
347 switch (prop->mType) {
348 case kTypeInt32:
349 prop->u.int32Value += value;
350 break;
351 default:
352 clearPropValue(prop);
353 prop->mType = kTypeInt32;
354 prop->u.int32Value = value;
355 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700356 }
Ray Essick3938dc62016-11-01 08:56:56 -0700357}
358
Ray Essickb5fac8e2016-12-12 11:33:56 -0800359void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
360 Prop *prop = allocateProp(name);
361 switch (prop->mType) {
362 case kTypeInt64:
363 prop->u.int64Value += value;
364 break;
365 default:
366 clearPropValue(prop);
367 prop->mType = kTypeInt64;
368 prop->u.int64Value = value;
369 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700370 }
Ray Essick3938dc62016-11-01 08:56:56 -0700371}
372
Ray Essickb5fac8e2016-12-12 11:33:56 -0800373void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
374 Prop *prop = allocateProp(name);
375 switch (prop->mType) {
376 case kTypeRate:
377 prop->u.rate.count += count;
378 prop->u.rate.duration += duration;
379 break;
380 default:
381 clearPropValue(prop);
382 prop->mType = kTypeRate;
383 prop->u.rate.count = count;
384 prop->u.rate.duration = duration;
385 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700386 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800387}
388
389void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
390 Prop *prop = allocateProp(name);
391 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);
461 if (prop == NULL || prop->mType != kTypeDouble) {
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
470// remove indicated keys and their values
471// return value is # keys removed
472int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
473 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800474 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700475 return -1;
476 }
477 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800478 const char *name = attrs[i];
479 size_t len = strlen(name);
480 size_t j = findPropIndex(name, len);
481 if (j >= mPropCount) {
482 // not there
483 continue;
484 } else if (j+1 == mPropCount) {
485 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700486 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800487 clearProp(&mProps[j]);
488 mPropCount--;
489 } else {
490 // in the middle, bring last one down and shorten
491 zapped++;
492 clearProp(&mProps[j]);
493 mProps[j] = mProps[mPropCount-1];
494 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700495 }
496 }
497 return zapped;
498}
499
500// remove any keys NOT in the provided list
501// return value is # keys removed
502int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
503 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800504 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700505 return -1;
506 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800507 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
508 Prop *prop = &mProps[i];
509 for (ssize_t j = 0; j < n ; j++) {
510 if (strcmp(prop->mName, attrs[j]) == 0) {
511 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700512 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800513 if (i != (ssize_t)(mPropCount-1)) {
514 *prop = mProps[mPropCount-1];
515 }
516 initProp(&mProps[mPropCount-1]);
517 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700518 break;
519 }
520 }
521 }
522 return zapped;
523}
524
525// remove a single key
526// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800527int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
528 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700529}
530
Ray Essick3938dc62016-11-01 08:56:56 -0700531// handle individual items/properties stored within the class
532//
Ray Essick3938dc62016-11-01 08:56:56 -0700533
Ray Essickb5fac8e2016-12-12 11:33:56 -0800534void MediaAnalyticsItem::initProp(Prop *prop) {
535 if (prop != NULL) {
536 prop->mName = NULL;
537 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700538
Ray Essickb5fac8e2016-12-12 11:33:56 -0800539 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700540 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800541}
542
543void MediaAnalyticsItem::clearProp(Prop *prop)
544{
545 if (prop != NULL) {
546 if (prop->mName != NULL) {
547 free((void *)prop->mName);
548 prop->mName = NULL;
549 prop->mNameLen = 0;
550 }
551
552 clearPropValue(prop);
553 }
554}
555
556void MediaAnalyticsItem::clearPropValue(Prop *prop)
557{
558 if (prop != NULL) {
559 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
560 free(prop->u.CStringValue);
561 prop->u.CStringValue = NULL;
562 }
563 prop->mType = kTypeNone;
564 }
565}
566
567void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
568{
569 // get rid of any pointers in the dst
570 clearProp(dst);
571
572 *dst = *src;
573
574 // fix any pointers that we blindly copied, so we have our own copies
575 if (dst->mName) {
576 void *p = malloc(dst->mNameLen + 1);
577 memcpy (p, src->mName, dst->mNameLen + 1);
578 dst->mName = (const char *) p;
579 }
580 if (dst->mType == kTypeCString) {
581 dst->u.CStringValue = strdup(src->u.CStringValue);
582 }
583}
584
585void MediaAnalyticsItem::growProps(int increment)
586{
587 if (increment <= 0) {
588 increment = kGrowProps;
589 }
590 int nsize = mPropSize + increment;
591 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
592
593 if (ni != NULL) {
594 for (int i = mPropSize; i < nsize; i++) {
595 initProp(&ni[i]);
596 }
597 mProps = ni;
598 mPropSize = nsize;
599 }
Ray Essick3938dc62016-11-01 08:56:56 -0700600}
601
602// Parcel / serialize things for binder calls
603//
604
605int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
606 // into 'this' object
607 // .. we make a copy of the string to put away.
608 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700609 mPid = data.readInt32();
610 mUid = data.readInt32();
611 mPkgName = data.readCString();
612 mPkgVersionCode = data.readInt32();
Ray Essick3938dc62016-11-01 08:56:56 -0700613 mSessionID = data.readInt64();
614 mFinalized = data.readInt32();
615 mTimestamp = data.readInt64();
616
617 int count = data.readInt32();
618 for (int i = 0; i < count ; i++) {
619 MediaAnalyticsItem::Attr attr = data.readCString();
620 int32_t ztype = data.readInt32();
621 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800622 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700623 setInt32(attr, data.readInt32());
624 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800625 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700626 setInt64(attr, data.readInt64());
627 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800628 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700629 setDouble(attr, data.readDouble());
630 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800631 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700632 setCString(attr, data.readCString());
633 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800634 case MediaAnalyticsItem::kTypeRate:
635 {
636 int64_t count = data.readInt64();
637 int64_t duration = data.readInt64();
638 setRate(attr, count, duration);
639 }
640 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700641 default:
642 ALOGE("reading bad item type: %d, idx %d",
643 ztype, i);
644 return -1;
645 }
646 }
647
648 return 0;
649}
650
651int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
652 if (data == NULL) return -1;
653
654
655 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700656 data->writeInt32(mPid);
657 data->writeInt32(mUid);
658 data->writeCString(mPkgName.c_str());
659 data->writeInt32(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700660 data->writeInt64(mSessionID);
661 data->writeInt32(mFinalized);
662 data->writeInt64(mTimestamp);
663
664 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800665 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700666 data->writeInt32(count);
667 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800668 Prop *prop = &mProps[i];
669 data->writeCString(prop->mName);
670 data->writeInt32(prop->mType);
671 switch (prop->mType) {
672 case MediaAnalyticsItem::kTypeInt32:
673 data->writeInt32(prop->u.int32Value);
674 break;
675 case MediaAnalyticsItem::kTypeInt64:
676 data->writeInt64(prop->u.int64Value);
677 break;
678 case MediaAnalyticsItem::kTypeDouble:
679 data->writeDouble(prop->u.doubleValue);
680 break;
681 case MediaAnalyticsItem::kTypeRate:
682 data->writeInt64(prop->u.rate.count);
683 data->writeInt64(prop->u.rate.duration);
684 break;
685 case MediaAnalyticsItem::kTypeCString:
686 data->writeCString(prop->u.CStringValue);
687 break;
688 default:
689 ALOGE("found bad Prop type: %d, idx %d, name %s",
690 prop->mType, i, prop->mName);
691 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700692 }
693 }
694
695 return 0;
696}
697
698
Ray Essick3938dc62016-11-01 08:56:56 -0700699AString MediaAnalyticsItem::toString() {
Ray Essickf65f4212017-08-31 11:41:19 -0700700 return toString(-1);
701}
Ray Essick3938dc62016-11-01 08:56:56 -0700702
Ray Essickf65f4212017-08-31 11:41:19 -0700703AString MediaAnalyticsItem::toString(int version) {
704
705 // v0 : released with 'o'
706 // v1 : bug fix (missing pid/finalized separator),
707 // adds apk name, apk version code
708
709 if (version <= PROTO_FIRST) {
710 // default to original v0 format, until proper parsers are in place
711 version = PROTO_V0;
712 } else if (version > PROTO_LAST) {
713 version = PROTO_LAST;
714 }
715
716 AString result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800717 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700718
Ray Essickf65f4212017-08-31 11:41:19 -0700719 if (version == PROTO_V0) {
720 result = "(";
721 } else {
722 snprintf(buffer, sizeof(buffer), "[%d:", version);
723 result.append(buffer);
724 }
725
Ray Essick3938dc62016-11-01 08:56:56 -0700726 // same order as we spill into the parcel, although not required
727 // key+session are our primary matching criteria
728 result.append(mKey.c_str());
729 result.append(":");
730 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
731 result.append(buffer);
732
Ray Essickf65f4212017-08-31 11:41:19 -0700733 snprintf(buffer, sizeof(buffer), "%d:", mUid);
734 result.append(buffer);
735
736 if (version >= PROTO_V1) {
737 result.append(mPkgName);
738 snprintf(buffer, sizeof(buffer), ":%d:", mPkgVersionCode);
739 result.append(buffer);
740 }
741
742 // in 'o' (v1) , the separator between pid and finalized was omitted
743 if (version <= PROTO_V0) {
744 snprintf(buffer, sizeof(buffer), "%d", mPid);
745 } else {
746 snprintf(buffer, sizeof(buffer), "%d:", mPid);
747 }
Ray Essick3938dc62016-11-01 08:56:56 -0700748 result.append(buffer);
749
750 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
751 result.append(buffer);
752 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
753 result.append(buffer);
754
755 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800756 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700757 snprintf(buffer, sizeof(buffer), "%d:", count);
758 result.append(buffer);
759 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800760 Prop *prop = &mProps[i];
761 switch (prop->mType) {
762 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700763 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800764 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700765 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800766 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700767 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800768 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700769 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800770 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700771 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800772 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700773 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800774 case MediaAnalyticsItem::kTypeRate:
775 snprintf(buffer,sizeof(buffer),
776 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
777 prop->u.rate.count, prop->u.rate.duration);
778 break;
779 case MediaAnalyticsItem::kTypeCString:
780 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700781 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800782 // XXX: sanitize string for ':' '='
783 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700784 buffer[0] = ':';
785 buffer[1] = '\0';
786 break;
787 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800788 ALOGE("to_String bad item type: %d for %s",
789 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700790 break;
791 }
792 result.append(buffer);
793 }
794
Ray Essickf65f4212017-08-31 11:41:19 -0700795 if (version == PROTO_V0) {
796 result.append(")");
797 } else {
798 result.append("]");
799 }
Ray Essick3938dc62016-11-01 08:56:56 -0700800
801 return result;
802}
803
804// for the lazy, we offer methods that finds the service and
805// calls the appropriate daemon
806bool MediaAnalyticsItem::selfrecord() {
807 return selfrecord(false);
808}
809
810bool MediaAnalyticsItem::selfrecord(bool forcenew) {
811
Ray Essickb5fac8e2016-12-12 11:33:56 -0800812 if (DEBUG_API) {
813 AString p = this->toString();
814 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
815 }
Ray Essick3938dc62016-11-01 08:56:56 -0700816
817 sp<IMediaAnalyticsService> svc = getInstance();
818
819 if (svc != NULL) {
820 svc->submit(this, forcenew);
821 return true;
822 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800823 AString p = this->toString();
824 ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700825 return false;
826 }
827}
828
829// get a connection we can reuse for most of our lifetime
830// static
831sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
832static Mutex sInitMutex;
833
834//static
835bool MediaAnalyticsItem::isEnabled() {
836 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
837
838 if (enabled == -1) {
839 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
840 }
841 if (enabled == -1) {
842 enabled = MediaAnalyticsItem::EnabledProperty_default;
843 }
844 if (enabled <= 0) {
845 return false;
846 }
847 return true;
848}
849
850//static
851sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800852 static const char *servicename = "media.metrics";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800853 static int tries_remaining = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700854 int enabled = isEnabled();
855
856 if (enabled == false) {
857 if (DEBUG_SERVICEACCESS) {
858 ALOGD("disabled");
859 }
860 return NULL;
861 }
862
Ray Essick79a89ef2017-04-24 15:52:54 -0700863 // completely skip logging from certain UIDs. We do this here
864 // to avoid the multi-second timeouts while we learn that
865 // sepolicy will not let us find the service.
866 // We do this only for a select set of UIDs
867 // The sepolicy protection is still in place, we just want a faster
868 // response from this specific, small set of uids.
869 {
870 uid_t uid = getuid();
871 switch (uid) {
872 case AID_RADIO: // telephony subsystem, RIL
873 return NULL;
874 break;
875 default:
876 // let sepolicy deny access if appropriate
877 break;
878 }
879 }
880
Ray Essick3938dc62016-11-01 08:56:56 -0700881 {
882 Mutex::Autolock _l(sInitMutex);
883 const char *badness = "";
884
Ray Essickb5fac8e2016-12-12 11:33:56 -0800885 // think of tries_remaining as telling us whether service==NULL because
886 // (1) we haven't tried to initialize it yet
887 // (2) we've tried to initialize it, but failed.
888 if (sAnalyticsService == NULL && tries_remaining > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700889 sp<IServiceManager> sm = defaultServiceManager();
890 if (sm != NULL) {
891 sp<IBinder> binder = sm->getService(String16(servicename));
892 if (binder != NULL) {
893 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
894 } else {
895 badness = "did not find service";
896 }
897 } else {
898 badness = "No Service Manager access";
899 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800900
901 if (sAnalyticsService == NULL) {
902 if (tries_remaining > 0) {
903 tries_remaining--;
904 }
905 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700906 ALOGD("Unable to bind to service %s: %s", servicename, badness);
907 }
908 }
909 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800910
Ray Essick3938dc62016-11-01 08:56:56 -0700911 return sAnalyticsService;
912 }
913}
914
915
916// merge the info from 'incoming' into this record.
917// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800918bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700919
920 // if I don't have key or session id, take them from incoming
921 // 'this' should never be missing both of them...
922 if (mKey.empty()) {
923 mKey = incoming->mKey;
924 } else if (mSessionID == 0) {
925 mSessionID = incoming->mSessionID;
926 }
927
928 // we always take the more recent 'finalized' value
929 setFinalized(incoming->getFinalized());
930
931 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800932 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700933 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800934 Prop *iprop = &incoming->mProps[i];
935 Prop *oprop = findProp(iprop->mName);
936 const char *p = iprop->mName;
937 size_t len = strlen(p);
938 char semantic = p[len-1];
Ray Essick3938dc62016-11-01 08:56:56 -0700939
Ray Essickb5fac8e2016-12-12 11:33:56 -0800940 if (oprop == NULL) {
941 // no oprop, so we insert the new one
942 oprop = allocateProp(p);
943 copyProp(oprop, iprop);
944 } else {
945 // merge iprop into oprop
946 switch (semantic) {
947 case '<': // first aka keep old)
948 /* nop */
949 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700950
Ray Essickb5fac8e2016-12-12 11:33:56 -0800951 default: // default is 'last'
952 case '>': // last (aka keep new)
953 copyProp(oprop, iprop);
954 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700955
Ray Essickb5fac8e2016-12-12 11:33:56 -0800956 case '+': /* sum */
957 // XXX validate numeric types, sum in place
958 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700959
Ray Essickb5fac8e2016-12-12 11:33:56 -0800960 }
Ray Essick3938dc62016-11-01 08:56:56 -0700961 }
962 }
963
964 // not sure when we'd return false...
965 return true;
966}
967
968} // namespace android
969