blob: 76397c798a135ce5bb3d0cfc659353cda2cbcdac [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
52const char * const MediaAnalyticsItem::EnabledProperty = "media.analytics.enabled";
53const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.analytics.enabled";
54const int MediaAnalyticsItem::EnabledProperty_default = 0;
55
56
57// access functions for the class
58MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickb5fac8e2016-12-12 11:33:56 -080059 : mPid(0),
Ray Essick3938dc62016-11-01 08:56:56 -070060 mUid(0),
61 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 Essickb5fac8e2016-12-12 11:33:56 -080070 : mPid(0),
Ray Essick3938dc62016-11-01 08:56:56 -070071 mUid(0),
72 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
95 // clean attributes
96 // contents of the attributes
97 for (size_t i = 0 ; i < mPropSize; i++ ) {
98 clearProp(&mProps[i]);
99 }
100 // the attribute records themselves
101 if (mProps != NULL) {
102 free(mProps);
103 mProps = NULL;
104 }
105 mPropSize = 0;
106 mPropCount = 0;
107
108 return;
109}
110
111// make a deep copy of myself
112MediaAnalyticsItem *MediaAnalyticsItem::dup() {
113 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
114
115 if (dst != NULL) {
116 // key as part of constructor
117 dst->mPid = this->mPid;
118 dst->mUid = this->mUid;
119 dst->mSessionID = this->mSessionID;
120 dst->mTimestamp = this->mTimestamp;
121 dst->mFinalized = this->mFinalized;
122
123 // properties aka attributes
124 dst->growProps(this->mPropCount);
125 for(size_t i=0;i<mPropCount;i++) {
126 copyProp(&dst->mProps[i], &this->mProps[i]);
127 }
128 dst->mPropCount = this->mPropCount;
129 }
130
131 return dst;
132}
133
Ray Essick3938dc62016-11-01 08:56:56 -0700134// so clients can send intermediate values to be overlaid later
135MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
136 mFinalized = value;
137 return *this;
138}
139
140bool MediaAnalyticsItem::getFinalized() const {
141 return mFinalized;
142}
143
144MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
145 mSessionID = id;
146 return *this;
147}
148
149MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
150 return mSessionID;
151}
152
153MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700154
155 if (mSessionID == SessionIDNone) {
156 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800157 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700158 sp<IMediaAnalyticsService> svc = getInstance();
159 if (svc != NULL) {
160 newid = svc->generateUniqueSessionID();
161 }
162 mSessionID = newid;
163 }
164
165 return mSessionID;
166}
167
168MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
169 mSessionID = MediaAnalyticsItem::SessionIDNone;
170 return *this;
171}
172
173MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
174 mTimestamp = ts;
175 return *this;
176}
177
178nsecs_t MediaAnalyticsItem::getTimestamp() const {
179 return mTimestamp;
180}
181
182MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
183 mPid = pid;
184 return *this;
185}
186
187pid_t MediaAnalyticsItem::getPid() const {
188 return mPid;
189}
190
191MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
192 mUid = uid;
193 return *this;
194}
195
196uid_t MediaAnalyticsItem::getUid() const {
197 return mUid;
198}
199
Ray Essickb5fac8e2016-12-12 11:33:56 -0800200// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700201MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700202 mKey = key;
203 return *this;
204}
205
206MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
207 return mKey;
208}
209
Ray Essickb5fac8e2016-12-12 11:33:56 -0800210// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700211int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800212 return mPropCount;
213}
214
215// find the proper entry in the list
216size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
217{
218 size_t i = 0;
219 for (; i < mPropCount; i++) {
220 Prop *prop = &mProps[i];
221 if (prop->mNameLen != len) {
222 continue;
223 }
224 if (memcmp(name, prop->mName, len) == 0) {
225 break;
226 }
227 }
228 return i;
229}
230
231MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
232 size_t len = strlen(name);
233 size_t i = findPropIndex(name, len);
234 if (i < mPropCount) {
235 return &mProps[i];
236 }
237 return NULL;
238}
239
240void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
241 mNameLen = len;
242 mName = (const char *) malloc(len+1);
243 memcpy ((void *)mName, name, len+1);
244}
245
246// used only as part of a storing operation
247MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
248 size_t len = strlen(name);
249 size_t i = findPropIndex(name, len);
250 Prop *prop;
251
252 if (i < mPropCount) {
253 prop = &mProps[i];
254 } else {
255 if (i == mPropSize) {
256 growProps();
257 // XXX: verify success
258 }
259 i = mPropCount++;
260 prop = &mProps[i];
261 prop->setName(name, len);
262 }
263
264 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700265}
266
267// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800268void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
269 Prop *prop = allocateProp(name);
270 prop->mType = kTypeInt32;
271 prop->u.int32Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700272}
273
Ray Essickb5fac8e2016-12-12 11:33:56 -0800274void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
275 Prop *prop = allocateProp(name);
276 prop->mType = kTypeInt64;
277 prop->u.int64Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700278}
279
Ray Essickb5fac8e2016-12-12 11:33:56 -0800280void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
281 Prop *prop = allocateProp(name);
282 prop->mType = kTypeDouble;
283 prop->u.doubleValue = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700284}
285
Ray Essickb5fac8e2016-12-12 11:33:56 -0800286void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
287
288 Prop *prop = allocateProp(name);
289 // any old value will be gone
290 prop->mType = kTypeCString;
291 prop->u.CStringValue = strdup(value);
Ray Essick3938dc62016-11-01 08:56:56 -0700292}
293
Ray Essickb5fac8e2016-12-12 11:33:56 -0800294void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
295 Prop *prop = allocateProp(name);
296 prop->mType = kTypeRate;
297 prop->u.rate.count = count;
298 prop->u.rate.duration = duration;
299}
300
301
Ray Essick3938dc62016-11-01 08:56:56 -0700302// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800303void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
304 Prop *prop = allocateProp(name);
305 switch (prop->mType) {
306 case kTypeInt32:
307 prop->u.int32Value += value;
308 break;
309 default:
310 clearPropValue(prop);
311 prop->mType = kTypeInt32;
312 prop->u.int32Value = value;
313 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700314 }
Ray Essick3938dc62016-11-01 08:56:56 -0700315}
316
Ray Essickb5fac8e2016-12-12 11:33:56 -0800317void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
318 Prop *prop = allocateProp(name);
319 switch (prop->mType) {
320 case kTypeInt64:
321 prop->u.int64Value += value;
322 break;
323 default:
324 clearPropValue(prop);
325 prop->mType = kTypeInt64;
326 prop->u.int64Value = value;
327 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700328 }
Ray Essick3938dc62016-11-01 08:56:56 -0700329}
330
Ray Essickb5fac8e2016-12-12 11:33:56 -0800331void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
332 Prop *prop = allocateProp(name);
333 switch (prop->mType) {
334 case kTypeRate:
335 prop->u.rate.count += count;
336 prop->u.rate.duration += duration;
337 break;
338 default:
339 clearPropValue(prop);
340 prop->mType = kTypeRate;
341 prop->u.rate.count = count;
342 prop->u.rate.duration = duration;
343 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700344 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800345}
346
347void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
348 Prop *prop = allocateProp(name);
349 switch (prop->mType) {
350 case kTypeDouble:
351 prop->u.doubleValue += value;
352 break;
353 default:
354 clearPropValue(prop);
355 prop->mType = kTypeDouble;
356 prop->u.doubleValue = value;
357 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700358 }
Ray Essick3938dc62016-11-01 08:56:56 -0700359}
360
361// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800362bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
363 Prop *prop = findProp(name);
364 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700365 return false;
366 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800367 if (value != NULL) {
368 *value = prop->u.int32Value;
369 }
Ray Essick3938dc62016-11-01 08:56:56 -0700370 return true;
371}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800372
373bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
374 Prop *prop = findProp(name);
375 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700376 return false;
377 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800378 if (value != NULL) {
379 *value = prop->u.int64Value;
380 }
Ray Essick3938dc62016-11-01 08:56:56 -0700381 return true;
382}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800383
384bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
385 Prop *prop = findProp(name);
386 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700387 return false;
388 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800389 if (count != NULL) {
390 *count = prop->u.rate.count;
391 }
392 if (duration != NULL) {
393 *duration = prop->u.rate.duration;
394 }
395 if (rate != NULL) {
396 double r = 0.0;
397 if (prop->u.rate.duration != 0) {
398 r = prop->u.rate.count / (double) prop->u.rate.duration;
399 }
400 *rate = r;
401 }
402 return true;
403}
404
405bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
406 Prop *prop = findProp(name);
407 if (prop == NULL || prop->mType != kTypeDouble) {
408 return false;
409 }
410 if (value != NULL) {
411 *value = prop->u.doubleValue;
412 }
Ray Essick3938dc62016-11-01 08:56:56 -0700413 return true;
414}
415
416// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800417bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
418 Prop *prop = findProp(name);
419 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700420 return false;
421 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800422 if (value != NULL) {
423 *value = strdup(prop->u.CStringValue);
424 }
Ray Essick3938dc62016-11-01 08:56:56 -0700425 return true;
426}
427
428// remove indicated keys and their values
429// return value is # keys removed
430int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
431 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800432 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700433 return -1;
434 }
435 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800436 const char *name = attrs[i];
437 size_t len = strlen(name);
438 size_t j = findPropIndex(name, len);
439 if (j >= mPropCount) {
440 // not there
441 continue;
442 } else if (j+1 == mPropCount) {
443 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700444 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800445 clearProp(&mProps[j]);
446 mPropCount--;
447 } else {
448 // in the middle, bring last one down and shorten
449 zapped++;
450 clearProp(&mProps[j]);
451 mProps[j] = mProps[mPropCount-1];
452 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700453 }
454 }
455 return zapped;
456}
457
458// remove any keys NOT in the provided list
459// return value is # keys removed
460int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
461 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800462 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700463 return -1;
464 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800465 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
466 Prop *prop = &mProps[i];
467 for (ssize_t j = 0; j < n ; j++) {
468 if (strcmp(prop->mName, attrs[j]) == 0) {
469 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700470 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800471 if (i != (ssize_t)(mPropCount-1)) {
472 *prop = mProps[mPropCount-1];
473 }
474 initProp(&mProps[mPropCount-1]);
475 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700476 break;
477 }
478 }
479 }
480 return zapped;
481}
482
483// remove a single key
484// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800485int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
486 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700487}
488
Ray Essick3938dc62016-11-01 08:56:56 -0700489// handle individual items/properties stored within the class
490//
Ray Essick3938dc62016-11-01 08:56:56 -0700491
Ray Essickb5fac8e2016-12-12 11:33:56 -0800492void MediaAnalyticsItem::initProp(Prop *prop) {
493 if (prop != NULL) {
494 prop->mName = NULL;
495 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700496
Ray Essickb5fac8e2016-12-12 11:33:56 -0800497 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700498 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800499}
500
501void MediaAnalyticsItem::clearProp(Prop *prop)
502{
503 if (prop != NULL) {
504 if (prop->mName != NULL) {
505 free((void *)prop->mName);
506 prop->mName = NULL;
507 prop->mNameLen = 0;
508 }
509
510 clearPropValue(prop);
511 }
512}
513
514void MediaAnalyticsItem::clearPropValue(Prop *prop)
515{
516 if (prop != NULL) {
517 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
518 free(prop->u.CStringValue);
519 prop->u.CStringValue = NULL;
520 }
521 prop->mType = kTypeNone;
522 }
523}
524
525void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
526{
527 // get rid of any pointers in the dst
528 clearProp(dst);
529
530 *dst = *src;
531
532 // fix any pointers that we blindly copied, so we have our own copies
533 if (dst->mName) {
534 void *p = malloc(dst->mNameLen + 1);
535 memcpy (p, src->mName, dst->mNameLen + 1);
536 dst->mName = (const char *) p;
537 }
538 if (dst->mType == kTypeCString) {
539 dst->u.CStringValue = strdup(src->u.CStringValue);
540 }
541}
542
543void MediaAnalyticsItem::growProps(int increment)
544{
545 if (increment <= 0) {
546 increment = kGrowProps;
547 }
548 int nsize = mPropSize + increment;
549 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
550
551 if (ni != NULL) {
552 for (int i = mPropSize; i < nsize; i++) {
553 initProp(&ni[i]);
554 }
555 mProps = ni;
556 mPropSize = nsize;
557 }
Ray Essick3938dc62016-11-01 08:56:56 -0700558}
559
560// Parcel / serialize things for binder calls
561//
562
563int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
564 // into 'this' object
565 // .. we make a copy of the string to put away.
566 mKey = data.readCString();
567 mSessionID = data.readInt64();
568 mFinalized = data.readInt32();
569 mTimestamp = data.readInt64();
570
571 int count = data.readInt32();
572 for (int i = 0; i < count ; i++) {
573 MediaAnalyticsItem::Attr attr = data.readCString();
574 int32_t ztype = data.readInt32();
575 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800576 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700577 setInt32(attr, data.readInt32());
578 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800579 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700580 setInt64(attr, data.readInt64());
581 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800582 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700583 setDouble(attr, data.readDouble());
584 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800585 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700586 setCString(attr, data.readCString());
587 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800588 case MediaAnalyticsItem::kTypeRate:
589 {
590 int64_t count = data.readInt64();
591 int64_t duration = data.readInt64();
592 setRate(attr, count, duration);
593 }
594 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700595 default:
596 ALOGE("reading bad item type: %d, idx %d",
597 ztype, i);
598 return -1;
599 }
600 }
601
602 return 0;
603}
604
605int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
606 if (data == NULL) return -1;
607
608
609 data->writeCString(mKey.c_str());
610 data->writeInt64(mSessionID);
611 data->writeInt32(mFinalized);
612 data->writeInt64(mTimestamp);
613
614 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800615 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700616 data->writeInt32(count);
617 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800618 Prop *prop = &mProps[i];
619 data->writeCString(prop->mName);
620 data->writeInt32(prop->mType);
621 switch (prop->mType) {
622 case MediaAnalyticsItem::kTypeInt32:
623 data->writeInt32(prop->u.int32Value);
624 break;
625 case MediaAnalyticsItem::kTypeInt64:
626 data->writeInt64(prop->u.int64Value);
627 break;
628 case MediaAnalyticsItem::kTypeDouble:
629 data->writeDouble(prop->u.doubleValue);
630 break;
631 case MediaAnalyticsItem::kTypeRate:
632 data->writeInt64(prop->u.rate.count);
633 data->writeInt64(prop->u.rate.duration);
634 break;
635 case MediaAnalyticsItem::kTypeCString:
636 data->writeCString(prop->u.CStringValue);
637 break;
638 default:
639 ALOGE("found bad Prop type: %d, idx %d, name %s",
640 prop->mType, i, prop->mName);
641 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700642 }
643 }
644
645 return 0;
646}
647
648
649
650AString MediaAnalyticsItem::toString() {
651
652 AString result = "(";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800653 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700654
655 // same order as we spill into the parcel, although not required
656 // key+session are our primary matching criteria
Ray Essickb5fac8e2016-12-12 11:33:56 -0800657 //RBE ALOGD("mKey.c_str");
Ray Essick3938dc62016-11-01 08:56:56 -0700658 result.append(mKey.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800659 //RBE ALOGD("post-mKey.c_str");
Ray Essick3938dc62016-11-01 08:56:56 -0700660 result.append(":");
661 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
662 result.append(buffer);
663
664 // we need these internally, but don't want to upload them
665 snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
666 result.append(buffer);
667
668 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
669 result.append(buffer);
670 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
671 result.append(buffer);
672
673 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800674 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700675 snprintf(buffer, sizeof(buffer), "%d:", count);
676 result.append(buffer);
677 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800678 Prop *prop = &mProps[i];
679 switch (prop->mType) {
680 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700681 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800682 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700683 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800684 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700685 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800686 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700687 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800688 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700689 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800690 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700691 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800692 case MediaAnalyticsItem::kTypeRate:
693 snprintf(buffer,sizeof(buffer),
694 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
695 prop->u.rate.count, prop->u.rate.duration);
696 break;
697 case MediaAnalyticsItem::kTypeCString:
698 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700699 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800700 // XXX: sanitize string for ':' '='
701 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700702 buffer[0] = ':';
703 buffer[1] = '\0';
704 break;
705 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800706 ALOGE("to_String bad item type: %d for %s",
707 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700708 break;
709 }
710 result.append(buffer);
711 }
712
713 result.append(")");
714
715 return result;
716}
717
718// for the lazy, we offer methods that finds the service and
719// calls the appropriate daemon
720bool MediaAnalyticsItem::selfrecord() {
721 return selfrecord(false);
722}
723
724bool MediaAnalyticsItem::selfrecord(bool forcenew) {
725
Ray Essickb5fac8e2016-12-12 11:33:56 -0800726 if (DEBUG_API) {
727 AString p = this->toString();
728 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
729 }
Ray Essick3938dc62016-11-01 08:56:56 -0700730
731 sp<IMediaAnalyticsService> svc = getInstance();
732
733 if (svc != NULL) {
734 svc->submit(this, forcenew);
735 return true;
736 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800737 AString p = this->toString();
738 ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700739 return false;
740 }
741}
742
743// get a connection we can reuse for most of our lifetime
744// static
745sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
746static Mutex sInitMutex;
747
748//static
749bool MediaAnalyticsItem::isEnabled() {
750 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
751
752 if (enabled == -1) {
753 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
754 }
755 if (enabled == -1) {
756 enabled = MediaAnalyticsItem::EnabledProperty_default;
757 }
758 if (enabled <= 0) {
759 return false;
760 }
761 return true;
762}
763
764//static
765sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
766 static const char *servicename = "media.analytics";
Ray Essickb5fac8e2016-12-12 11:33:56 -0800767 static int tries_remaining = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700768 int enabled = isEnabled();
769
770 if (enabled == false) {
771 if (DEBUG_SERVICEACCESS) {
772 ALOGD("disabled");
773 }
774 return NULL;
775 }
776
777 {
778 Mutex::Autolock _l(sInitMutex);
779 const char *badness = "";
780
Ray Essickb5fac8e2016-12-12 11:33:56 -0800781 // think of tries_remaining as telling us whether service==NULL because
782 // (1) we haven't tried to initialize it yet
783 // (2) we've tried to initialize it, but failed.
784 if (sAnalyticsService == NULL && tries_remaining > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700785 sp<IServiceManager> sm = defaultServiceManager();
786 if (sm != NULL) {
787 sp<IBinder> binder = sm->getService(String16(servicename));
788 if (binder != NULL) {
789 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
790 } else {
791 badness = "did not find service";
792 }
793 } else {
794 badness = "No Service Manager access";
795 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800796
797 if (sAnalyticsService == NULL) {
798 if (tries_remaining > 0) {
799 tries_remaining--;
800 }
801 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700802 ALOGD("Unable to bind to service %s: %s", servicename, badness);
803 }
804 }
805 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800806
Ray Essick3938dc62016-11-01 08:56:56 -0700807 return sAnalyticsService;
808 }
809}
810
811
812// merge the info from 'incoming' into this record.
813// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800814bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700815
816 // if I don't have key or session id, take them from incoming
817 // 'this' should never be missing both of them...
818 if (mKey.empty()) {
819 mKey = incoming->mKey;
820 } else if (mSessionID == 0) {
821 mSessionID = incoming->mSessionID;
822 }
823
824 // we always take the more recent 'finalized' value
825 setFinalized(incoming->getFinalized());
826
827 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800828 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700829 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800830 Prop *iprop = &incoming->mProps[i];
831 Prop *oprop = findProp(iprop->mName);
832 const char *p = iprop->mName;
833 size_t len = strlen(p);
834 char semantic = p[len-1];
Ray Essick3938dc62016-11-01 08:56:56 -0700835
Ray Essickb5fac8e2016-12-12 11:33:56 -0800836 if (oprop == NULL) {
837 // no oprop, so we insert the new one
838 oprop = allocateProp(p);
839 copyProp(oprop, iprop);
840 } else {
841 // merge iprop into oprop
842 switch (semantic) {
843 case '<': // first aka keep old)
844 /* nop */
845 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700846
Ray Essickb5fac8e2016-12-12 11:33:56 -0800847 default: // default is 'last'
848 case '>': // last (aka keep new)
849 copyProp(oprop, iprop);
850 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700851
Ray Essickb5fac8e2016-12-12 11:33:56 -0800852 case '+': /* sum */
853 // XXX validate numeric types, sum in place
854 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700855
Ray Essickb5fac8e2016-12-12 11:33:56 -0800856 }
Ray Essick3938dc62016-11-01 08:56:56 -0700857 }
858 }
859
860 // not sure when we'd return false...
861 return true;
862}
863
864} // namespace android
865