blob: 43881b339e935caf79f7ab2c8fd463e0adf71a9c [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;
123 dst->mSessionID = this->mSessionID;
124 dst->mTimestamp = this->mTimestamp;
125 dst->mFinalized = this->mFinalized;
126
127 // properties aka attributes
128 dst->growProps(this->mPropCount);
129 for(size_t i=0;i<mPropCount;i++) {
130 copyProp(&dst->mProps[i], &this->mProps[i]);
131 }
132 dst->mPropCount = this->mPropCount;
133 }
134
135 return dst;
136}
137
Ray Essick3938dc62016-11-01 08:56:56 -0700138// so clients can send intermediate values to be overlaid later
139MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
140 mFinalized = value;
141 return *this;
142}
143
144bool MediaAnalyticsItem::getFinalized() const {
145 return mFinalized;
146}
147
148MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
149 mSessionID = id;
150 return *this;
151}
152
153MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
154 return mSessionID;
155}
156
157MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700158
159 if (mSessionID == SessionIDNone) {
160 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800161 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700162 sp<IMediaAnalyticsService> svc = getInstance();
163 if (svc != NULL) {
164 newid = svc->generateUniqueSessionID();
165 }
166 mSessionID = newid;
167 }
168
169 return mSessionID;
170}
171
172MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
173 mSessionID = MediaAnalyticsItem::SessionIDNone;
174 return *this;
175}
176
177MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
178 mTimestamp = ts;
179 return *this;
180}
181
182nsecs_t MediaAnalyticsItem::getTimestamp() const {
183 return mTimestamp;
184}
185
186MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
187 mPid = pid;
188 return *this;
189}
190
191pid_t MediaAnalyticsItem::getPid() const {
192 return mPid;
193}
194
195MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
196 mUid = uid;
197 return *this;
198}
199
200uid_t MediaAnalyticsItem::getUid() const {
201 return mUid;
202}
203
Ray Essickb5fac8e2016-12-12 11:33:56 -0800204// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700205MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700206 mKey = key;
207 return *this;
208}
209
210MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
211 return mKey;
212}
213
Ray Essickb5fac8e2016-12-12 11:33:56 -0800214// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700215int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800216 return mPropCount;
217}
218
219// find the proper entry in the list
220size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
221{
222 size_t i = 0;
223 for (; i < mPropCount; i++) {
224 Prop *prop = &mProps[i];
225 if (prop->mNameLen != len) {
226 continue;
227 }
228 if (memcmp(name, prop->mName, len) == 0) {
229 break;
230 }
231 }
232 return i;
233}
234
235MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
236 size_t len = strlen(name);
237 size_t i = findPropIndex(name, len);
238 if (i < mPropCount) {
239 return &mProps[i];
240 }
241 return NULL;
242}
243
244void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
245 mNameLen = len;
246 mName = (const char *) malloc(len+1);
247 memcpy ((void *)mName, name, len+1);
248}
249
250// used only as part of a storing operation
251MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
252 size_t len = strlen(name);
253 size_t i = findPropIndex(name, len);
254 Prop *prop;
255
256 if (i < mPropCount) {
257 prop = &mProps[i];
258 } else {
259 if (i == mPropSize) {
260 growProps();
261 // XXX: verify success
262 }
263 i = mPropCount++;
264 prop = &mProps[i];
265 prop->setName(name, len);
266 }
267
268 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700269}
270
271// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800272void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
273 Prop *prop = allocateProp(name);
274 prop->mType = kTypeInt32;
275 prop->u.int32Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700276}
277
Ray Essickb5fac8e2016-12-12 11:33:56 -0800278void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
279 Prop *prop = allocateProp(name);
280 prop->mType = kTypeInt64;
281 prop->u.int64Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700282}
283
Ray Essickb5fac8e2016-12-12 11:33:56 -0800284void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
285 Prop *prop = allocateProp(name);
286 prop->mType = kTypeDouble;
287 prop->u.doubleValue = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700288}
289
Ray Essickb5fac8e2016-12-12 11:33:56 -0800290void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
291
292 Prop *prop = allocateProp(name);
293 // any old value will be gone
294 prop->mType = kTypeCString;
295 prop->u.CStringValue = strdup(value);
Ray Essick3938dc62016-11-01 08:56:56 -0700296}
297
Ray Essickb5fac8e2016-12-12 11:33:56 -0800298void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
299 Prop *prop = allocateProp(name);
300 prop->mType = kTypeRate;
301 prop->u.rate.count = count;
302 prop->u.rate.duration = duration;
303}
304
305
Ray Essick3938dc62016-11-01 08:56:56 -0700306// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800307void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
308 Prop *prop = allocateProp(name);
309 switch (prop->mType) {
310 case kTypeInt32:
311 prop->u.int32Value += value;
312 break;
313 default:
314 clearPropValue(prop);
315 prop->mType = kTypeInt32;
316 prop->u.int32Value = value;
317 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700318 }
Ray Essick3938dc62016-11-01 08:56:56 -0700319}
320
Ray Essickb5fac8e2016-12-12 11:33:56 -0800321void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
322 Prop *prop = allocateProp(name);
323 switch (prop->mType) {
324 case kTypeInt64:
325 prop->u.int64Value += value;
326 break;
327 default:
328 clearPropValue(prop);
329 prop->mType = kTypeInt64;
330 prop->u.int64Value = value;
331 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700332 }
Ray Essick3938dc62016-11-01 08:56:56 -0700333}
334
Ray Essickb5fac8e2016-12-12 11:33:56 -0800335void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
336 Prop *prop = allocateProp(name);
337 switch (prop->mType) {
338 case kTypeRate:
339 prop->u.rate.count += count;
340 prop->u.rate.duration += duration;
341 break;
342 default:
343 clearPropValue(prop);
344 prop->mType = kTypeRate;
345 prop->u.rate.count = count;
346 prop->u.rate.duration = duration;
347 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700348 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800349}
350
351void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
352 Prop *prop = allocateProp(name);
353 switch (prop->mType) {
354 case kTypeDouble:
355 prop->u.doubleValue += value;
356 break;
357 default:
358 clearPropValue(prop);
359 prop->mType = kTypeDouble;
360 prop->u.doubleValue = value;
361 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700362 }
Ray Essick3938dc62016-11-01 08:56:56 -0700363}
364
365// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800366bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
367 Prop *prop = findProp(name);
368 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700369 return false;
370 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800371 if (value != NULL) {
372 *value = prop->u.int32Value;
373 }
Ray Essick3938dc62016-11-01 08:56:56 -0700374 return true;
375}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800376
377bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
378 Prop *prop = findProp(name);
379 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700380 return false;
381 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800382 if (value != NULL) {
383 *value = prop->u.int64Value;
384 }
Ray Essick3938dc62016-11-01 08:56:56 -0700385 return true;
386}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800387
388bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
389 Prop *prop = findProp(name);
390 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700391 return false;
392 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800393 if (count != NULL) {
394 *count = prop->u.rate.count;
395 }
396 if (duration != NULL) {
397 *duration = prop->u.rate.duration;
398 }
399 if (rate != NULL) {
400 double r = 0.0;
401 if (prop->u.rate.duration != 0) {
402 r = prop->u.rate.count / (double) prop->u.rate.duration;
403 }
404 *rate = r;
405 }
406 return true;
407}
408
409bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
410 Prop *prop = findProp(name);
411 if (prop == NULL || prop->mType != kTypeDouble) {
412 return false;
413 }
414 if (value != NULL) {
415 *value = prop->u.doubleValue;
416 }
Ray Essick3938dc62016-11-01 08:56:56 -0700417 return true;
418}
419
420// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800421bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
422 Prop *prop = findProp(name);
423 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700424 return false;
425 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800426 if (value != NULL) {
427 *value = strdup(prop->u.CStringValue);
428 }
Ray Essick3938dc62016-11-01 08:56:56 -0700429 return true;
430}
431
432// remove indicated keys and their values
433// return value is # keys removed
434int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
435 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800436 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700437 return -1;
438 }
439 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800440 const char *name = attrs[i];
441 size_t len = strlen(name);
442 size_t j = findPropIndex(name, len);
443 if (j >= mPropCount) {
444 // not there
445 continue;
446 } else if (j+1 == mPropCount) {
447 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700448 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800449 clearProp(&mProps[j]);
450 mPropCount--;
451 } else {
452 // in the middle, bring last one down and shorten
453 zapped++;
454 clearProp(&mProps[j]);
455 mProps[j] = mProps[mPropCount-1];
456 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700457 }
458 }
459 return zapped;
460}
461
462// remove any keys NOT in the provided list
463// return value is # keys removed
464int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
465 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800466 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700467 return -1;
468 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800469 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
470 Prop *prop = &mProps[i];
471 for (ssize_t j = 0; j < n ; j++) {
472 if (strcmp(prop->mName, attrs[j]) == 0) {
473 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700474 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800475 if (i != (ssize_t)(mPropCount-1)) {
476 *prop = mProps[mPropCount-1];
477 }
478 initProp(&mProps[mPropCount-1]);
479 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700480 break;
481 }
482 }
483 }
484 return zapped;
485}
486
487// remove a single key
488// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800489int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
490 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700491}
492
Ray Essick3938dc62016-11-01 08:56:56 -0700493// handle individual items/properties stored within the class
494//
Ray Essick3938dc62016-11-01 08:56:56 -0700495
Ray Essickb5fac8e2016-12-12 11:33:56 -0800496void MediaAnalyticsItem::initProp(Prop *prop) {
497 if (prop != NULL) {
498 prop->mName = NULL;
499 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700500
Ray Essickb5fac8e2016-12-12 11:33:56 -0800501 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700502 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800503}
504
505void MediaAnalyticsItem::clearProp(Prop *prop)
506{
507 if (prop != NULL) {
508 if (prop->mName != NULL) {
509 free((void *)prop->mName);
510 prop->mName = NULL;
511 prop->mNameLen = 0;
512 }
513
514 clearPropValue(prop);
515 }
516}
517
518void MediaAnalyticsItem::clearPropValue(Prop *prop)
519{
520 if (prop != NULL) {
521 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
522 free(prop->u.CStringValue);
523 prop->u.CStringValue = NULL;
524 }
525 prop->mType = kTypeNone;
526 }
527}
528
529void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
530{
531 // get rid of any pointers in the dst
532 clearProp(dst);
533
534 *dst = *src;
535
536 // fix any pointers that we blindly copied, so we have our own copies
537 if (dst->mName) {
538 void *p = malloc(dst->mNameLen + 1);
539 memcpy (p, src->mName, dst->mNameLen + 1);
540 dst->mName = (const char *) p;
541 }
542 if (dst->mType == kTypeCString) {
543 dst->u.CStringValue = strdup(src->u.CStringValue);
544 }
545}
546
547void MediaAnalyticsItem::growProps(int increment)
548{
549 if (increment <= 0) {
550 increment = kGrowProps;
551 }
552 int nsize = mPropSize + increment;
553 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
554
555 if (ni != NULL) {
556 for (int i = mPropSize; i < nsize; i++) {
557 initProp(&ni[i]);
558 }
559 mProps = ni;
560 mPropSize = nsize;
561 }
Ray Essick3938dc62016-11-01 08:56:56 -0700562}
563
564// Parcel / serialize things for binder calls
565//
566
567int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
568 // into 'this' object
569 // .. we make a copy of the string to put away.
570 mKey = data.readCString();
571 mSessionID = data.readInt64();
572 mFinalized = data.readInt32();
573 mTimestamp = data.readInt64();
574
575 int count = data.readInt32();
576 for (int i = 0; i < count ; i++) {
577 MediaAnalyticsItem::Attr attr = data.readCString();
578 int32_t ztype = data.readInt32();
579 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800580 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700581 setInt32(attr, data.readInt32());
582 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800583 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700584 setInt64(attr, data.readInt64());
585 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800586 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700587 setDouble(attr, data.readDouble());
588 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800589 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700590 setCString(attr, data.readCString());
591 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800592 case MediaAnalyticsItem::kTypeRate:
593 {
594 int64_t count = data.readInt64();
595 int64_t duration = data.readInt64();
596 setRate(attr, count, duration);
597 }
598 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700599 default:
600 ALOGE("reading bad item type: %d, idx %d",
601 ztype, i);
602 return -1;
603 }
604 }
605
606 return 0;
607}
608
609int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
610 if (data == NULL) return -1;
611
612
613 data->writeCString(mKey.c_str());
614 data->writeInt64(mSessionID);
615 data->writeInt32(mFinalized);
616 data->writeInt64(mTimestamp);
617
618 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800619 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700620 data->writeInt32(count);
621 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800622 Prop *prop = &mProps[i];
623 data->writeCString(prop->mName);
624 data->writeInt32(prop->mType);
625 switch (prop->mType) {
626 case MediaAnalyticsItem::kTypeInt32:
627 data->writeInt32(prop->u.int32Value);
628 break;
629 case MediaAnalyticsItem::kTypeInt64:
630 data->writeInt64(prop->u.int64Value);
631 break;
632 case MediaAnalyticsItem::kTypeDouble:
633 data->writeDouble(prop->u.doubleValue);
634 break;
635 case MediaAnalyticsItem::kTypeRate:
636 data->writeInt64(prop->u.rate.count);
637 data->writeInt64(prop->u.rate.duration);
638 break;
639 case MediaAnalyticsItem::kTypeCString:
640 data->writeCString(prop->u.CStringValue);
641 break;
642 default:
643 ALOGE("found bad Prop type: %d, idx %d, name %s",
644 prop->mType, i, prop->mName);
645 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700646 }
647 }
648
649 return 0;
650}
651
652
Ray Essick3938dc62016-11-01 08:56:56 -0700653AString MediaAnalyticsItem::toString() {
654
655 AString result = "(";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800656 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700657
658 // same order as we spill into the parcel, although not required
659 // key+session are our primary matching criteria
Ray Essickb5fac8e2016-12-12 11:33:56 -0800660 //RBE ALOGD("mKey.c_str");
Ray Essick3938dc62016-11-01 08:56:56 -0700661 result.append(mKey.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800662 //RBE ALOGD("post-mKey.c_str");
Ray Essick3938dc62016-11-01 08:56:56 -0700663 result.append(":");
664 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
665 result.append(buffer);
666
667 // we need these internally, but don't want to upload them
668 snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
669 result.append(buffer);
670
671 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
672 result.append(buffer);
673 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
674 result.append(buffer);
675
676 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800677 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700678 snprintf(buffer, sizeof(buffer), "%d:", count);
679 result.append(buffer);
680 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800681 Prop *prop = &mProps[i];
682 switch (prop->mType) {
683 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700684 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800685 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700686 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800687 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700688 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800689 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700690 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800691 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700692 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800693 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700694 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800695 case MediaAnalyticsItem::kTypeRate:
696 snprintf(buffer,sizeof(buffer),
697 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
698 prop->u.rate.count, prop->u.rate.duration);
699 break;
700 case MediaAnalyticsItem::kTypeCString:
701 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700702 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800703 // XXX: sanitize string for ':' '='
704 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700705 buffer[0] = ':';
706 buffer[1] = '\0';
707 break;
708 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800709 ALOGE("to_String bad item type: %d for %s",
710 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700711 break;
712 }
713 result.append(buffer);
714 }
715
716 result.append(")");
717
718 return result;
719}
720
721// for the lazy, we offer methods that finds the service and
722// calls the appropriate daemon
723bool MediaAnalyticsItem::selfrecord() {
724 return selfrecord(false);
725}
726
727bool MediaAnalyticsItem::selfrecord(bool forcenew) {
728
Ray Essickb5fac8e2016-12-12 11:33:56 -0800729 if (DEBUG_API) {
730 AString p = this->toString();
731 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
732 }
Ray Essick3938dc62016-11-01 08:56:56 -0700733
734 sp<IMediaAnalyticsService> svc = getInstance();
735
736 if (svc != NULL) {
737 svc->submit(this, forcenew);
738 return true;
739 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800740 AString p = this->toString();
741 ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700742 return false;
743 }
744}
745
746// get a connection we can reuse for most of our lifetime
747// static
748sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
749static Mutex sInitMutex;
750
751//static
752bool MediaAnalyticsItem::isEnabled() {
753 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
754
755 if (enabled == -1) {
756 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
757 }
758 if (enabled == -1) {
759 enabled = MediaAnalyticsItem::EnabledProperty_default;
760 }
761 if (enabled <= 0) {
762 return false;
763 }
764 return true;
765}
766
767//static
768sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800769 static const char *servicename = "media.metrics";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800770 static int tries_remaining = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700771 int enabled = isEnabled();
772
773 if (enabled == false) {
774 if (DEBUG_SERVICEACCESS) {
775 ALOGD("disabled");
776 }
777 return NULL;
778 }
779
Ray Essick79a89ef2017-04-24 15:52:54 -0700780 // completely skip logging from certain UIDs. We do this here
781 // to avoid the multi-second timeouts while we learn that
782 // sepolicy will not let us find the service.
783 // We do this only for a select set of UIDs
784 // The sepolicy protection is still in place, we just want a faster
785 // response from this specific, small set of uids.
786 {
787 uid_t uid = getuid();
788 switch (uid) {
789 case AID_RADIO: // telephony subsystem, RIL
790 return NULL;
791 break;
792 default:
793 // let sepolicy deny access if appropriate
794 break;
795 }
796 }
797
Ray Essick3938dc62016-11-01 08:56:56 -0700798 {
799 Mutex::Autolock _l(sInitMutex);
800 const char *badness = "";
801
Ray Essickb5fac8e2016-12-12 11:33:56 -0800802 // think of tries_remaining as telling us whether service==NULL because
803 // (1) we haven't tried to initialize it yet
804 // (2) we've tried to initialize it, but failed.
805 if (sAnalyticsService == NULL && tries_remaining > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700806 sp<IServiceManager> sm = defaultServiceManager();
807 if (sm != NULL) {
808 sp<IBinder> binder = sm->getService(String16(servicename));
809 if (binder != NULL) {
810 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
811 } else {
812 badness = "did not find service";
813 }
814 } else {
815 badness = "No Service Manager access";
816 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800817
818 if (sAnalyticsService == NULL) {
819 if (tries_remaining > 0) {
820 tries_remaining--;
821 }
822 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700823 ALOGD("Unable to bind to service %s: %s", servicename, badness);
824 }
825 }
826 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800827
Ray Essick3938dc62016-11-01 08:56:56 -0700828 return sAnalyticsService;
829 }
830}
831
832
833// merge the info from 'incoming' into this record.
834// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800835bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700836
837 // if I don't have key or session id, take them from incoming
838 // 'this' should never be missing both of them...
839 if (mKey.empty()) {
840 mKey = incoming->mKey;
841 } else if (mSessionID == 0) {
842 mSessionID = incoming->mSessionID;
843 }
844
845 // we always take the more recent 'finalized' value
846 setFinalized(incoming->getFinalized());
847
848 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800849 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700850 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800851 Prop *iprop = &incoming->mProps[i];
852 Prop *oprop = findProp(iprop->mName);
853 const char *p = iprop->mName;
854 size_t len = strlen(p);
855 char semantic = p[len-1];
Ray Essick3938dc62016-11-01 08:56:56 -0700856
Ray Essickb5fac8e2016-12-12 11:33:56 -0800857 if (oprop == NULL) {
858 // no oprop, so we insert the new one
859 oprop = allocateProp(p);
860 copyProp(oprop, iprop);
861 } else {
862 // merge iprop into oprop
863 switch (semantic) {
864 case '<': // first aka keep old)
865 /* nop */
866 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700867
Ray Essickb5fac8e2016-12-12 11:33:56 -0800868 default: // default is 'last'
869 case '>': // last (aka keep new)
870 copyProp(oprop, iprop);
871 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700872
Ray Essickb5fac8e2016-12-12 11:33:56 -0800873 case '+': /* sum */
874 // XXX validate numeric types, sum in place
875 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700876
Ray Essickb5fac8e2016-12-12 11:33:56 -0800877 }
Ray Essick3938dc62016-11-01 08:56:56 -0700878 }
879 }
880
881 // not sure when we'd return false...
882 return true;
883}
884
885} // namespace android
886