blob: 375d1d5d40391f81b9efa490e88966f9a4919634 [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>
37
38namespace android {
39
40#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080041#define DEBUG_API 0
42#define DEBUG_ALLOCATIONS 0
43
44// after this many failed attempts, we stop trying [from this process] and just say that
45// the service is off.
46#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070047
48// the few universal keys we have
49const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
50const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
51
Ray Essickd38e1742017-01-23 15:17:06 -080052const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
53const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
Ray Essick3938dc62016-11-01 08:56:56 -070054const int MediaAnalyticsItem::EnabledProperty_default = 0;
55
56
57// access functions for the class
58MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080059 : mPid(-1),
60 mUid(-1),
Ray Essick3938dc62016-11-01 08:56:56 -070061 mSessionID(MediaAnalyticsItem::SessionIDNone),
62 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080063 mFinalized(0),
64 mPropCount(0), mPropSize(0), mProps(NULL)
65{
Ray Essick3938dc62016-11-01 08:56:56 -070066 mKey = MediaAnalyticsItem::kKeyNone;
67}
68
69MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080070 : mPid(-1),
71 mUid(-1),
Ray Essick3938dc62016-11-01 08:56:56 -070072 mSessionID(MediaAnalyticsItem::SessionIDNone),
73 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080074 mFinalized(0),
75 mPropCount(0), mPropSize(0), mProps(NULL)
76{
77 if (DEBUG_ALLOCATIONS) {
78 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
79 }
Ray Essick3938dc62016-11-01 08:56:56 -070080 mKey = key;
81}
82
83MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080084 if (DEBUG_ALLOCATIONS) {
85 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
86 }
Ray Essick3938dc62016-11-01 08:56:56 -070087 clear();
88}
89
Ray Essickb5fac8e2016-12-12 11:33:56 -080090void MediaAnalyticsItem::clear() {
91
92 // clean allocated storage from key
93 mKey.clear();
94
Ray Essickd38e1742017-01-23 15:17:06 -080095 // clean various major parameters
96 mSessionID = MediaAnalyticsItem::SessionIDNone;
97
Ray Essickb5fac8e2016-12-12 11:33:56 -080098 // clean attributes
99 // contents of the attributes
100 for (size_t i = 0 ; i < mPropSize; i++ ) {
101 clearProp(&mProps[i]);
102 }
103 // the attribute records themselves
104 if (mProps != NULL) {
105 free(mProps);
106 mProps = NULL;
107 }
108 mPropSize = 0;
109 mPropCount = 0;
110
111 return;
112}
113
114// make a deep copy of myself
115MediaAnalyticsItem *MediaAnalyticsItem::dup() {
116 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
117
118 if (dst != NULL) {
119 // key as part of constructor
120 dst->mPid = this->mPid;
121 dst->mUid = this->mUid;
122 dst->mSessionID = this->mSessionID;
123 dst->mTimestamp = this->mTimestamp;
124 dst->mFinalized = this->mFinalized;
125
126 // properties aka attributes
127 dst->growProps(this->mPropCount);
128 for(size_t i=0;i<mPropCount;i++) {
129 copyProp(&dst->mProps[i], &this->mProps[i]);
130 }
131 dst->mPropCount = this->mPropCount;
132 }
133
134 return dst;
135}
136
Ray Essick3938dc62016-11-01 08:56:56 -0700137// so clients can send intermediate values to be overlaid later
138MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
139 mFinalized = value;
140 return *this;
141}
142
143bool MediaAnalyticsItem::getFinalized() const {
144 return mFinalized;
145}
146
147MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
148 mSessionID = id;
149 return *this;
150}
151
152MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
153 return mSessionID;
154}
155
156MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700157
158 if (mSessionID == SessionIDNone) {
159 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800160 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700161 sp<IMediaAnalyticsService> svc = getInstance();
162 if (svc != NULL) {
163 newid = svc->generateUniqueSessionID();
164 }
165 mSessionID = newid;
166 }
167
168 return mSessionID;
169}
170
171MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
172 mSessionID = MediaAnalyticsItem::SessionIDNone;
173 return *this;
174}
175
176MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
177 mTimestamp = ts;
178 return *this;
179}
180
181nsecs_t MediaAnalyticsItem::getTimestamp() const {
182 return mTimestamp;
183}
184
185MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
186 mPid = pid;
187 return *this;
188}
189
190pid_t MediaAnalyticsItem::getPid() const {
191 return mPid;
192}
193
194MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
195 mUid = uid;
196 return *this;
197}
198
199uid_t MediaAnalyticsItem::getUid() const {
200 return mUid;
201}
202
Ray Essickb5fac8e2016-12-12 11:33:56 -0800203// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700204MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700205 mKey = key;
206 return *this;
207}
208
209MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
210 return mKey;
211}
212
Ray Essickb5fac8e2016-12-12 11:33:56 -0800213// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700214int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800215 return mPropCount;
216}
217
218// find the proper entry in the list
219size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
220{
221 size_t i = 0;
222 for (; i < mPropCount; i++) {
223 Prop *prop = &mProps[i];
224 if (prop->mNameLen != len) {
225 continue;
226 }
227 if (memcmp(name, prop->mName, len) == 0) {
228 break;
229 }
230 }
231 return i;
232}
233
234MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
235 size_t len = strlen(name);
236 size_t i = findPropIndex(name, len);
237 if (i < mPropCount) {
238 return &mProps[i];
239 }
240 return NULL;
241}
242
243void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
244 mNameLen = len;
245 mName = (const char *) malloc(len+1);
246 memcpy ((void *)mName, name, len+1);
247}
248
249// used only as part of a storing operation
250MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
251 size_t len = strlen(name);
252 size_t i = findPropIndex(name, len);
253 Prop *prop;
254
255 if (i < mPropCount) {
256 prop = &mProps[i];
257 } else {
258 if (i == mPropSize) {
259 growProps();
260 // XXX: verify success
261 }
262 i = mPropCount++;
263 prop = &mProps[i];
264 prop->setName(name, len);
265 }
266
267 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700268}
269
270// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800271void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
272 Prop *prop = allocateProp(name);
273 prop->mType = kTypeInt32;
274 prop->u.int32Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700275}
276
Ray Essickb5fac8e2016-12-12 11:33:56 -0800277void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
278 Prop *prop = allocateProp(name);
279 prop->mType = kTypeInt64;
280 prop->u.int64Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700281}
282
Ray Essickb5fac8e2016-12-12 11:33:56 -0800283void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
284 Prop *prop = allocateProp(name);
285 prop->mType = kTypeDouble;
286 prop->u.doubleValue = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700287}
288
Ray Essickb5fac8e2016-12-12 11:33:56 -0800289void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
290
291 Prop *prop = allocateProp(name);
292 // any old value will be gone
293 prop->mType = kTypeCString;
294 prop->u.CStringValue = strdup(value);
Ray Essick3938dc62016-11-01 08:56:56 -0700295}
296
Ray Essickb5fac8e2016-12-12 11:33:56 -0800297void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
298 Prop *prop = allocateProp(name);
299 prop->mType = kTypeRate;
300 prop->u.rate.count = count;
301 prop->u.rate.duration = duration;
302}
303
304
Ray Essick3938dc62016-11-01 08:56:56 -0700305// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800306void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
307 Prop *prop = allocateProp(name);
308 switch (prop->mType) {
309 case kTypeInt32:
310 prop->u.int32Value += value;
311 break;
312 default:
313 clearPropValue(prop);
314 prop->mType = kTypeInt32;
315 prop->u.int32Value = value;
316 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700317 }
Ray Essick3938dc62016-11-01 08:56:56 -0700318}
319
Ray Essickb5fac8e2016-12-12 11:33:56 -0800320void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
321 Prop *prop = allocateProp(name);
322 switch (prop->mType) {
323 case kTypeInt64:
324 prop->u.int64Value += value;
325 break;
326 default:
327 clearPropValue(prop);
328 prop->mType = kTypeInt64;
329 prop->u.int64Value = value;
330 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700331 }
Ray Essick3938dc62016-11-01 08:56:56 -0700332}
333
Ray Essickb5fac8e2016-12-12 11:33:56 -0800334void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
335 Prop *prop = allocateProp(name);
336 switch (prop->mType) {
337 case kTypeRate:
338 prop->u.rate.count += count;
339 prop->u.rate.duration += duration;
340 break;
341 default:
342 clearPropValue(prop);
343 prop->mType = kTypeRate;
344 prop->u.rate.count = count;
345 prop->u.rate.duration = duration;
346 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700347 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800348}
349
350void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
351 Prop *prop = allocateProp(name);
352 switch (prop->mType) {
353 case kTypeDouble:
354 prop->u.doubleValue += value;
355 break;
356 default:
357 clearPropValue(prop);
358 prop->mType = kTypeDouble;
359 prop->u.doubleValue = value;
360 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700361 }
Ray Essick3938dc62016-11-01 08:56:56 -0700362}
363
364// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800365bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
366 Prop *prop = findProp(name);
367 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700368 return false;
369 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800370 if (value != NULL) {
371 *value = prop->u.int32Value;
372 }
Ray Essick3938dc62016-11-01 08:56:56 -0700373 return true;
374}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800375
376bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
377 Prop *prop = findProp(name);
378 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700379 return false;
380 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800381 if (value != NULL) {
382 *value = prop->u.int64Value;
383 }
Ray Essick3938dc62016-11-01 08:56:56 -0700384 return true;
385}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800386
387bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
388 Prop *prop = findProp(name);
389 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700390 return false;
391 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800392 if (count != NULL) {
393 *count = prop->u.rate.count;
394 }
395 if (duration != NULL) {
396 *duration = prop->u.rate.duration;
397 }
398 if (rate != NULL) {
399 double r = 0.0;
400 if (prop->u.rate.duration != 0) {
401 r = prop->u.rate.count / (double) prop->u.rate.duration;
402 }
403 *rate = r;
404 }
405 return true;
406}
407
408bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
409 Prop *prop = findProp(name);
410 if (prop == NULL || prop->mType != kTypeDouble) {
411 return false;
412 }
413 if (value != NULL) {
414 *value = prop->u.doubleValue;
415 }
Ray Essick3938dc62016-11-01 08:56:56 -0700416 return true;
417}
418
419// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800420bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
421 Prop *prop = findProp(name);
422 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700423 return false;
424 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800425 if (value != NULL) {
426 *value = strdup(prop->u.CStringValue);
427 }
Ray Essick3938dc62016-11-01 08:56:56 -0700428 return true;
429}
430
431// remove indicated keys and their values
432// return value is # keys removed
433int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
434 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800435 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700436 return -1;
437 }
438 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800439 const char *name = attrs[i];
440 size_t len = strlen(name);
441 size_t j = findPropIndex(name, len);
442 if (j >= mPropCount) {
443 // not there
444 continue;
445 } else if (j+1 == mPropCount) {
446 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700447 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800448 clearProp(&mProps[j]);
449 mPropCount--;
450 } else {
451 // in the middle, bring last one down and shorten
452 zapped++;
453 clearProp(&mProps[j]);
454 mProps[j] = mProps[mPropCount-1];
455 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700456 }
457 }
458 return zapped;
459}
460
461// remove any keys NOT in the provided list
462// return value is # keys removed
463int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
464 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800465 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700466 return -1;
467 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800468 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
469 Prop *prop = &mProps[i];
470 for (ssize_t j = 0; j < n ; j++) {
471 if (strcmp(prop->mName, attrs[j]) == 0) {
472 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700473 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800474 if (i != (ssize_t)(mPropCount-1)) {
475 *prop = mProps[mPropCount-1];
476 }
477 initProp(&mProps[mPropCount-1]);
478 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700479 break;
480 }
481 }
482 }
483 return zapped;
484}
485
486// remove a single key
487// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800488int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
489 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700490}
491
Ray Essick3938dc62016-11-01 08:56:56 -0700492// handle individual items/properties stored within the class
493//
Ray Essick3938dc62016-11-01 08:56:56 -0700494
Ray Essickb5fac8e2016-12-12 11:33:56 -0800495void MediaAnalyticsItem::initProp(Prop *prop) {
496 if (prop != NULL) {
497 prop->mName = NULL;
498 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700499
Ray Essickb5fac8e2016-12-12 11:33:56 -0800500 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700501 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800502}
503
504void MediaAnalyticsItem::clearProp(Prop *prop)
505{
506 if (prop != NULL) {
507 if (prop->mName != NULL) {
508 free((void *)prop->mName);
509 prop->mName = NULL;
510 prop->mNameLen = 0;
511 }
512
513 clearPropValue(prop);
514 }
515}
516
517void MediaAnalyticsItem::clearPropValue(Prop *prop)
518{
519 if (prop != NULL) {
520 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
521 free(prop->u.CStringValue);
522 prop->u.CStringValue = NULL;
523 }
524 prop->mType = kTypeNone;
525 }
526}
527
528void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
529{
530 // get rid of any pointers in the dst
531 clearProp(dst);
532
533 *dst = *src;
534
535 // fix any pointers that we blindly copied, so we have our own copies
536 if (dst->mName) {
537 void *p = malloc(dst->mNameLen + 1);
538 memcpy (p, src->mName, dst->mNameLen + 1);
539 dst->mName = (const char *) p;
540 }
541 if (dst->mType == kTypeCString) {
542 dst->u.CStringValue = strdup(src->u.CStringValue);
543 }
544}
545
546void MediaAnalyticsItem::growProps(int increment)
547{
548 if (increment <= 0) {
549 increment = kGrowProps;
550 }
551 int nsize = mPropSize + increment;
552 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
553
554 if (ni != NULL) {
555 for (int i = mPropSize; i < nsize; i++) {
556 initProp(&ni[i]);
557 }
558 mProps = ni;
559 mPropSize = nsize;
560 }
Ray Essick3938dc62016-11-01 08:56:56 -0700561}
562
563// Parcel / serialize things for binder calls
564//
565
566int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
567 // into 'this' object
568 // .. we make a copy of the string to put away.
569 mKey = data.readCString();
570 mSessionID = data.readInt64();
571 mFinalized = data.readInt32();
572 mTimestamp = data.readInt64();
573
574 int count = data.readInt32();
575 for (int i = 0; i < count ; i++) {
576 MediaAnalyticsItem::Attr attr = data.readCString();
577 int32_t ztype = data.readInt32();
578 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800579 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700580 setInt32(attr, data.readInt32());
581 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800582 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700583 setInt64(attr, data.readInt64());
584 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800585 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700586 setDouble(attr, data.readDouble());
587 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800588 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700589 setCString(attr, data.readCString());
590 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800591 case MediaAnalyticsItem::kTypeRate:
592 {
593 int64_t count = data.readInt64();
594 int64_t duration = data.readInt64();
595 setRate(attr, count, duration);
596 }
597 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700598 default:
599 ALOGE("reading bad item type: %d, idx %d",
600 ztype, i);
601 return -1;
602 }
603 }
604
605 return 0;
606}
607
608int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
609 if (data == NULL) return -1;
610
611
612 data->writeCString(mKey.c_str());
613 data->writeInt64(mSessionID);
614 data->writeInt32(mFinalized);
615 data->writeInt64(mTimestamp);
616
617 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800618 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700619 data->writeInt32(count);
620 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800621 Prop *prop = &mProps[i];
622 data->writeCString(prop->mName);
623 data->writeInt32(prop->mType);
624 switch (prop->mType) {
625 case MediaAnalyticsItem::kTypeInt32:
626 data->writeInt32(prop->u.int32Value);
627 break;
628 case MediaAnalyticsItem::kTypeInt64:
629 data->writeInt64(prop->u.int64Value);
630 break;
631 case MediaAnalyticsItem::kTypeDouble:
632 data->writeDouble(prop->u.doubleValue);
633 break;
634 case MediaAnalyticsItem::kTypeRate:
635 data->writeInt64(prop->u.rate.count);
636 data->writeInt64(prop->u.rate.duration);
637 break;
638 case MediaAnalyticsItem::kTypeCString:
639 data->writeCString(prop->u.CStringValue);
640 break;
641 default:
642 ALOGE("found bad Prop type: %d, idx %d, name %s",
643 prop->mType, i, prop->mName);
644 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700645 }
646 }
647
648 return 0;
649}
650
651
Ray Essick3938dc62016-11-01 08:56:56 -0700652AString MediaAnalyticsItem::toString() {
653
654 AString result = "(";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800655 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700656
657 // same order as we spill into the parcel, although not required
658 // key+session are our primary matching criteria
Ray Essickb5fac8e2016-12-12 11:33:56 -0800659 //RBE ALOGD("mKey.c_str");
Ray Essick3938dc62016-11-01 08:56:56 -0700660 result.append(mKey.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800661 //RBE ALOGD("post-mKey.c_str");
Ray Essick3938dc62016-11-01 08:56:56 -0700662 result.append(":");
663 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
664 result.append(buffer);
665
666 // we need these internally, but don't want to upload them
667 snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
668 result.append(buffer);
669
670 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
671 result.append(buffer);
672 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
673 result.append(buffer);
674
675 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800676 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700677 snprintf(buffer, sizeof(buffer), "%d:", count);
678 result.append(buffer);
679 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800680 Prop *prop = &mProps[i];
681 switch (prop->mType) {
682 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700683 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800684 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700685 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800686 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700687 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800688 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700689 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800690 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700691 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800692 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700693 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800694 case MediaAnalyticsItem::kTypeRate:
695 snprintf(buffer,sizeof(buffer),
696 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
697 prop->u.rate.count, prop->u.rate.duration);
698 break;
699 case MediaAnalyticsItem::kTypeCString:
700 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700701 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800702 // XXX: sanitize string for ':' '='
703 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700704 buffer[0] = ':';
705 buffer[1] = '\0';
706 break;
707 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800708 ALOGE("to_String bad item type: %d for %s",
709 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700710 break;
711 }
712 result.append(buffer);
713 }
714
715 result.append(")");
716
717 return result;
718}
719
720// for the lazy, we offer methods that finds the service and
721// calls the appropriate daemon
722bool MediaAnalyticsItem::selfrecord() {
723 return selfrecord(false);
724}
725
726bool MediaAnalyticsItem::selfrecord(bool forcenew) {
727
Ray Essickb5fac8e2016-12-12 11:33:56 -0800728 if (DEBUG_API) {
729 AString p = this->toString();
730 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
731 }
Ray Essick3938dc62016-11-01 08:56:56 -0700732
733 sp<IMediaAnalyticsService> svc = getInstance();
734
735 if (svc != NULL) {
736 svc->submit(this, forcenew);
737 return true;
738 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800739 AString p = this->toString();
740 ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700741 return false;
742 }
743}
744
745// get a connection we can reuse for most of our lifetime
746// static
747sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
748static Mutex sInitMutex;
749
750//static
751bool MediaAnalyticsItem::isEnabled() {
752 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
753
754 if (enabled == -1) {
755 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
756 }
757 if (enabled == -1) {
758 enabled = MediaAnalyticsItem::EnabledProperty_default;
759 }
760 if (enabled <= 0) {
761 return false;
762 }
763 return true;
764}
765
766//static
767sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800768 static const char *servicename = "media.metrics";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800769 static int tries_remaining = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700770 int enabled = isEnabled();
771
772 if (enabled == false) {
773 if (DEBUG_SERVICEACCESS) {
774 ALOGD("disabled");
775 }
776 return NULL;
777 }
778
779 {
780 Mutex::Autolock _l(sInitMutex);
781 const char *badness = "";
782
Ray Essickb5fac8e2016-12-12 11:33:56 -0800783 // think of tries_remaining as telling us whether service==NULL because
784 // (1) we haven't tried to initialize it yet
785 // (2) we've tried to initialize it, but failed.
786 if (sAnalyticsService == NULL && tries_remaining > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700787 sp<IServiceManager> sm = defaultServiceManager();
788 if (sm != NULL) {
789 sp<IBinder> binder = sm->getService(String16(servicename));
790 if (binder != NULL) {
791 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
792 } else {
793 badness = "did not find service";
794 }
795 } else {
796 badness = "No Service Manager access";
797 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800798
799 if (sAnalyticsService == NULL) {
800 if (tries_remaining > 0) {
801 tries_remaining--;
802 }
803 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700804 ALOGD("Unable to bind to service %s: %s", servicename, badness);
805 }
806 }
807 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800808
Ray Essick3938dc62016-11-01 08:56:56 -0700809 return sAnalyticsService;
810 }
811}
812
813
814// merge the info from 'incoming' into this record.
815// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800816bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700817
818 // if I don't have key or session id, take them from incoming
819 // 'this' should never be missing both of them...
820 if (mKey.empty()) {
821 mKey = incoming->mKey;
822 } else if (mSessionID == 0) {
823 mSessionID = incoming->mSessionID;
824 }
825
826 // we always take the more recent 'finalized' value
827 setFinalized(incoming->getFinalized());
828
829 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800830 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700831 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800832 Prop *iprop = &incoming->mProps[i];
833 Prop *oprop = findProp(iprop->mName);
834 const char *p = iprop->mName;
835 size_t len = strlen(p);
836 char semantic = p[len-1];
Ray Essick3938dc62016-11-01 08:56:56 -0700837
Ray Essickb5fac8e2016-12-12 11:33:56 -0800838 if (oprop == NULL) {
839 // no oprop, so we insert the new one
840 oprop = allocateProp(p);
841 copyProp(oprop, iprop);
842 } else {
843 // merge iprop into oprop
844 switch (semantic) {
845 case '<': // first aka keep old)
846 /* nop */
847 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700848
Ray Essickb5fac8e2016-12-12 11:33:56 -0800849 default: // default is 'last'
850 case '>': // last (aka keep new)
851 copyProp(oprop, iprop);
852 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700853
Ray Essickb5fac8e2016-12-12 11:33:56 -0800854 case '+': /* sum */
855 // XXX validate numeric types, sum in place
856 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700857
Ray Essickb5fac8e2016-12-12 11:33:56 -0800858 }
Ray Essick3938dc62016-11-01 08:56:56 -0700859 }
860 }
861
862 // not sure when we'd return false...
863 return true;
864}
865
866} // namespace android
867