blob: f7df2b4864c8e5b38d3eab0f535847170c12ef53 [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 Essickfa149562017-09-19 09:27:31 -070062 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070063 mSessionID(MediaAnalyticsItem::SessionIDNone),
64 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080065 mFinalized(0),
66 mPropCount(0), mPropSize(0), mProps(NULL)
67{
Ray Essick3938dc62016-11-01 08:56:56 -070068 mKey = MediaAnalyticsItem::kKeyNone;
69}
70
71MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080072 : mPid(-1),
73 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070074 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070075 mSessionID(MediaAnalyticsItem::SessionIDNone),
76 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080077 mFinalized(0),
78 mPropCount(0), mPropSize(0), mProps(NULL)
79{
80 if (DEBUG_ALLOCATIONS) {
81 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
82 }
Ray Essick3938dc62016-11-01 08:56:56 -070083 mKey = key;
84}
85
86MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080087 if (DEBUG_ALLOCATIONS) {
88 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
89 }
Ray Essick3938dc62016-11-01 08:56:56 -070090 clear();
91}
92
Ray Essickb5fac8e2016-12-12 11:33:56 -080093void MediaAnalyticsItem::clear() {
94
95 // clean allocated storage from key
96 mKey.clear();
97
Ray Essickd38e1742017-01-23 15:17:06 -080098 // clean various major parameters
99 mSessionID = MediaAnalyticsItem::SessionIDNone;
100
Ray Essickb5fac8e2016-12-12 11:33:56 -0800101 // clean attributes
102 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700103 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800104 clearProp(&mProps[i]);
105 }
106 // the attribute records themselves
107 if (mProps != NULL) {
108 free(mProps);
109 mProps = NULL;
110 }
111 mPropSize = 0;
112 mPropCount = 0;
113
114 return;
115}
116
117// make a deep copy of myself
118MediaAnalyticsItem *MediaAnalyticsItem::dup() {
119 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
120
121 if (dst != NULL) {
122 // key as part of constructor
123 dst->mPid = this->mPid;
124 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700125 dst->mPkgName = this->mPkgName;
126 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800127 dst->mSessionID = this->mSessionID;
128 dst->mTimestamp = this->mTimestamp;
129 dst->mFinalized = this->mFinalized;
130
131 // properties aka attributes
132 dst->growProps(this->mPropCount);
133 for(size_t i=0;i<mPropCount;i++) {
134 copyProp(&dst->mProps[i], &this->mProps[i]);
135 }
136 dst->mPropCount = this->mPropCount;
137 }
138
139 return dst;
140}
141
Ray Essick3938dc62016-11-01 08:56:56 -0700142// so clients can send intermediate values to be overlaid later
143MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
144 mFinalized = value;
145 return *this;
146}
147
148bool MediaAnalyticsItem::getFinalized() const {
149 return mFinalized;
150}
151
152MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
153 mSessionID = id;
154 return *this;
155}
156
157MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
158 return mSessionID;
159}
160
161MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700162
163 if (mSessionID == SessionIDNone) {
164 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800165 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700166 sp<IMediaAnalyticsService> svc = getInstance();
167 if (svc != NULL) {
168 newid = svc->generateUniqueSessionID();
169 }
170 mSessionID = newid;
171 }
172
173 return mSessionID;
174}
175
176MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
177 mSessionID = MediaAnalyticsItem::SessionIDNone;
178 return *this;
179}
180
181MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
182 mTimestamp = ts;
183 return *this;
184}
185
186nsecs_t MediaAnalyticsItem::getTimestamp() const {
187 return mTimestamp;
188}
189
190MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
191 mPid = pid;
192 return *this;
193}
194
195pid_t MediaAnalyticsItem::getPid() const {
196 return mPid;
197}
198
199MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
200 mUid = uid;
201 return *this;
202}
203
204uid_t MediaAnalyticsItem::getUid() const {
205 return mUid;
206}
207
Ray Essickf65f4212017-08-31 11:41:19 -0700208MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
209 mPkgName = pkgName;
210 return *this;
211}
212
213AString MediaAnalyticsItem::getPkgName() const {
214 return mPkgName;
215}
216
217MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int32_t pkgVersionCode) {
218 mPkgVersionCode = pkgVersionCode;
219 return *this;
220}
221
222int32_t MediaAnalyticsItem::getPkgVersionCode() const {
223 return mPkgVersionCode;
224}
225
Ray Essickb5fac8e2016-12-12 11:33:56 -0800226// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700227MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700228 mKey = key;
229 return *this;
230}
231
232MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
233 return mKey;
234}
235
Ray Essickb5fac8e2016-12-12 11:33:56 -0800236// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700237int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800238 return mPropCount;
239}
240
241// find the proper entry in the list
242size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
243{
244 size_t i = 0;
245 for (; i < mPropCount; i++) {
246 Prop *prop = &mProps[i];
247 if (prop->mNameLen != len) {
248 continue;
249 }
250 if (memcmp(name, prop->mName, len) == 0) {
251 break;
252 }
253 }
254 return i;
255}
256
257MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
258 size_t len = strlen(name);
259 size_t i = findPropIndex(name, len);
260 if (i < mPropCount) {
261 return &mProps[i];
262 }
263 return NULL;
264}
265
266void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
267 mNameLen = len;
268 mName = (const char *) malloc(len+1);
269 memcpy ((void *)mName, name, len+1);
270}
271
272// used only as part of a storing operation
273MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
274 size_t len = strlen(name);
275 size_t i = findPropIndex(name, len);
276 Prop *prop;
277
278 if (i < mPropCount) {
279 prop = &mProps[i];
280 } else {
281 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700282 if (growProps() == false) {
283 ALOGE("failed allocation for new props");
284 return NULL;
285 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800286 }
287 i = mPropCount++;
288 prop = &mProps[i];
289 prop->setName(name, len);
Ray Essickf65f4212017-08-31 11:41:19 -0700290 prop->mType = kTypeNone; // make caller set type info
Ray Essickb5fac8e2016-12-12 11:33:56 -0800291 }
292
293 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700294}
295
Ray Essickf65f4212017-08-31 11:41:19 -0700296// used within the summarizers; return whether property existed
297bool MediaAnalyticsItem::removeProp(const char *name) {
298 size_t len = strlen(name);
299 size_t i = findPropIndex(name, len);
300 if (i < mPropCount) {
301 Prop *prop = &mProps[i];
302 clearProp(prop);
303 if (i != mPropCount-1) {
304 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700305 copyProp(prop, &mProps[mPropCount-1]);
306 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700307 }
308 mPropCount--;
309 return true;
310 }
311 return false;
312}
313
Ray Essick3938dc62016-11-01 08:56:56 -0700314// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800315void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
316 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700317 if (prop != NULL) {
318 prop->mType = kTypeInt32;
319 prop->u.int32Value = value;
320 }
Ray Essick3938dc62016-11-01 08:56:56 -0700321}
322
Ray Essickb5fac8e2016-12-12 11:33:56 -0800323void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
324 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700325 if (prop != NULL) {
326 prop->mType = kTypeInt64;
327 prop->u.int64Value = value;
328 }
Ray Essick3938dc62016-11-01 08:56:56 -0700329}
330
Ray Essickb5fac8e2016-12-12 11:33:56 -0800331void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
332 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700333 if (prop != NULL) {
334 prop->mType = kTypeDouble;
335 prop->u.doubleValue = value;
336 }
Ray Essick3938dc62016-11-01 08:56:56 -0700337}
338
Ray Essickb5fac8e2016-12-12 11:33:56 -0800339void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
340
341 Prop *prop = allocateProp(name);
342 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700343 if (prop != NULL) {
344 prop->mType = kTypeCString;
345 prop->u.CStringValue = strdup(value);
346 }
Ray Essick3938dc62016-11-01 08:56:56 -0700347}
348
Ray Essickb5fac8e2016-12-12 11:33:56 -0800349void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
350 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700351 if (prop != NULL) {
352 prop->mType = kTypeRate;
353 prop->u.rate.count = count;
354 prop->u.rate.duration = duration;
355 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800356}
357
358
Ray Essick3938dc62016-11-01 08:56:56 -0700359// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800360void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
361 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700362 if (prop == NULL) {
363 return;
364 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800365 switch (prop->mType) {
366 case kTypeInt32:
367 prop->u.int32Value += value;
368 break;
369 default:
370 clearPropValue(prop);
371 prop->mType = kTypeInt32;
372 prop->u.int32Value = value;
373 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700374 }
Ray Essick3938dc62016-11-01 08:56:56 -0700375}
376
Ray Essickb5fac8e2016-12-12 11:33:56 -0800377void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
378 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700379 if (prop == NULL) {
380 return;
381 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800382 switch (prop->mType) {
383 case kTypeInt64:
384 prop->u.int64Value += value;
385 break;
386 default:
387 clearPropValue(prop);
388 prop->mType = kTypeInt64;
389 prop->u.int64Value = value;
390 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700391 }
Ray Essick3938dc62016-11-01 08:56:56 -0700392}
393
Ray Essickb5fac8e2016-12-12 11:33:56 -0800394void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
395 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700396 if (prop == NULL) {
397 return;
398 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800399 switch (prop->mType) {
400 case kTypeRate:
401 prop->u.rate.count += count;
402 prop->u.rate.duration += duration;
403 break;
404 default:
405 clearPropValue(prop);
406 prop->mType = kTypeRate;
407 prop->u.rate.count = count;
408 prop->u.rate.duration = duration;
409 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700410 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800411}
412
413void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
414 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700415 if (prop == NULL) {
416 return;
417 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800418 switch (prop->mType) {
419 case kTypeDouble:
420 prop->u.doubleValue += value;
421 break;
422 default:
423 clearPropValue(prop);
424 prop->mType = kTypeDouble;
425 prop->u.doubleValue = value;
426 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700427 }
Ray Essick3938dc62016-11-01 08:56:56 -0700428}
429
430// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800431bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
432 Prop *prop = findProp(name);
433 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700434 return false;
435 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800436 if (value != NULL) {
437 *value = prop->u.int32Value;
438 }
Ray Essick3938dc62016-11-01 08:56:56 -0700439 return true;
440}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800441
442bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
443 Prop *prop = findProp(name);
444 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700445 return false;
446 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800447 if (value != NULL) {
448 *value = prop->u.int64Value;
449 }
Ray Essick3938dc62016-11-01 08:56:56 -0700450 return true;
451}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800452
453bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
454 Prop *prop = findProp(name);
455 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700456 return false;
457 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800458 if (count != NULL) {
459 *count = prop->u.rate.count;
460 }
461 if (duration != NULL) {
462 *duration = prop->u.rate.duration;
463 }
464 if (rate != NULL) {
465 double r = 0.0;
466 if (prop->u.rate.duration != 0) {
467 r = prop->u.rate.count / (double) prop->u.rate.duration;
468 }
469 *rate = r;
470 }
471 return true;
472}
473
474bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
475 Prop *prop = findProp(name);
476 if (prop == NULL || prop->mType != kTypeDouble) {
477 return false;
478 }
479 if (value != NULL) {
480 *value = prop->u.doubleValue;
481 }
Ray Essick3938dc62016-11-01 08:56:56 -0700482 return true;
483}
484
485// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800486bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
487 Prop *prop = findProp(name);
488 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700489 return false;
490 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800491 if (value != NULL) {
492 *value = strdup(prop->u.CStringValue);
493 }
Ray Essick3938dc62016-11-01 08:56:56 -0700494 return true;
495}
496
497// remove indicated keys and their values
498// return value is # keys removed
499int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
500 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800501 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700502 return -1;
503 }
504 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800505 const char *name = attrs[i];
506 size_t len = strlen(name);
507 size_t j = findPropIndex(name, len);
508 if (j >= mPropCount) {
509 // not there
510 continue;
511 } else if (j+1 == mPropCount) {
512 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700513 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800514 clearProp(&mProps[j]);
515 mPropCount--;
516 } else {
517 // in the middle, bring last one down and shorten
518 zapped++;
519 clearProp(&mProps[j]);
520 mProps[j] = mProps[mPropCount-1];
521 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700522 }
523 }
524 return zapped;
525}
526
527// remove any keys NOT in the provided list
528// return value is # keys removed
529int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
530 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800531 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700532 return -1;
533 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800534 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
535 Prop *prop = &mProps[i];
536 for (ssize_t j = 0; j < n ; j++) {
537 if (strcmp(prop->mName, attrs[j]) == 0) {
538 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700539 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800540 if (i != (ssize_t)(mPropCount-1)) {
541 *prop = mProps[mPropCount-1];
542 }
543 initProp(&mProps[mPropCount-1]);
544 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700545 break;
546 }
547 }
548 }
549 return zapped;
550}
551
552// remove a single key
553// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800554int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
555 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700556}
557
Ray Essick3938dc62016-11-01 08:56:56 -0700558// handle individual items/properties stored within the class
559//
Ray Essick3938dc62016-11-01 08:56:56 -0700560
Ray Essickb5fac8e2016-12-12 11:33:56 -0800561void MediaAnalyticsItem::initProp(Prop *prop) {
562 if (prop != NULL) {
563 prop->mName = NULL;
564 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700565
Ray Essickb5fac8e2016-12-12 11:33:56 -0800566 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700567 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800568}
569
570void MediaAnalyticsItem::clearProp(Prop *prop)
571{
572 if (prop != NULL) {
573 if (prop->mName != NULL) {
574 free((void *)prop->mName);
575 prop->mName = NULL;
576 prop->mNameLen = 0;
577 }
578
579 clearPropValue(prop);
580 }
581}
582
583void MediaAnalyticsItem::clearPropValue(Prop *prop)
584{
585 if (prop != NULL) {
586 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
587 free(prop->u.CStringValue);
588 prop->u.CStringValue = NULL;
589 }
590 prop->mType = kTypeNone;
591 }
592}
593
594void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
595{
596 // get rid of any pointers in the dst
597 clearProp(dst);
598
599 *dst = *src;
600
601 // fix any pointers that we blindly copied, so we have our own copies
602 if (dst->mName) {
603 void *p = malloc(dst->mNameLen + 1);
604 memcpy (p, src->mName, dst->mNameLen + 1);
605 dst->mName = (const char *) p;
606 }
607 if (dst->mType == kTypeCString) {
608 dst->u.CStringValue = strdup(src->u.CStringValue);
609 }
610}
611
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700612bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800613{
614 if (increment <= 0) {
615 increment = kGrowProps;
616 }
617 int nsize = mPropSize + increment;
618 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
619
620 if (ni != NULL) {
621 for (int i = mPropSize; i < nsize; i++) {
622 initProp(&ni[i]);
623 }
624 mProps = ni;
625 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700626 return true;
627 } else {
628 ALOGW("MediaAnalyticsItem::growProps fails");
629 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800630 }
Ray Essick3938dc62016-11-01 08:56:56 -0700631}
632
633// Parcel / serialize things for binder calls
634//
635
636int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
637 // into 'this' object
638 // .. we make a copy of the string to put away.
639 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700640 mPid = data.readInt32();
641 mUid = data.readInt32();
642 mPkgName = data.readCString();
643 mPkgVersionCode = data.readInt32();
Ray Essick3938dc62016-11-01 08:56:56 -0700644 mSessionID = data.readInt64();
645 mFinalized = data.readInt32();
646 mTimestamp = data.readInt64();
647
648 int count = data.readInt32();
649 for (int i = 0; i < count ; i++) {
650 MediaAnalyticsItem::Attr attr = data.readCString();
651 int32_t ztype = data.readInt32();
652 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800653 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700654 setInt32(attr, data.readInt32());
655 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800656 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700657 setInt64(attr, data.readInt64());
658 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800659 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700660 setDouble(attr, data.readDouble());
661 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800662 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700663 setCString(attr, data.readCString());
664 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800665 case MediaAnalyticsItem::kTypeRate:
666 {
667 int64_t count = data.readInt64();
668 int64_t duration = data.readInt64();
669 setRate(attr, count, duration);
670 }
671 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700672 default:
673 ALOGE("reading bad item type: %d, idx %d",
674 ztype, i);
675 return -1;
676 }
677 }
678
679 return 0;
680}
681
682int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
683 if (data == NULL) return -1;
684
685
686 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700687 data->writeInt32(mPid);
688 data->writeInt32(mUid);
689 data->writeCString(mPkgName.c_str());
690 data->writeInt32(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700691 data->writeInt64(mSessionID);
692 data->writeInt32(mFinalized);
693 data->writeInt64(mTimestamp);
694
695 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800696 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700697 data->writeInt32(count);
698 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800699 Prop *prop = &mProps[i];
700 data->writeCString(prop->mName);
701 data->writeInt32(prop->mType);
702 switch (prop->mType) {
703 case MediaAnalyticsItem::kTypeInt32:
704 data->writeInt32(prop->u.int32Value);
705 break;
706 case MediaAnalyticsItem::kTypeInt64:
707 data->writeInt64(prop->u.int64Value);
708 break;
709 case MediaAnalyticsItem::kTypeDouble:
710 data->writeDouble(prop->u.doubleValue);
711 break;
712 case MediaAnalyticsItem::kTypeRate:
713 data->writeInt64(prop->u.rate.count);
714 data->writeInt64(prop->u.rate.duration);
715 break;
716 case MediaAnalyticsItem::kTypeCString:
717 data->writeCString(prop->u.CStringValue);
718 break;
719 default:
720 ALOGE("found bad Prop type: %d, idx %d, name %s",
721 prop->mType, i, prop->mName);
722 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700723 }
724 }
725
726 return 0;
727}
728
729
Ray Essick3938dc62016-11-01 08:56:56 -0700730AString MediaAnalyticsItem::toString() {
Ray Essickf65f4212017-08-31 11:41:19 -0700731 return toString(-1);
732}
Ray Essick3938dc62016-11-01 08:56:56 -0700733
Ray Essickf65f4212017-08-31 11:41:19 -0700734AString MediaAnalyticsItem::toString(int version) {
735
736 // v0 : released with 'o'
737 // v1 : bug fix (missing pid/finalized separator),
738 // adds apk name, apk version code
739
740 if (version <= PROTO_FIRST) {
741 // default to original v0 format, until proper parsers are in place
742 version = PROTO_V0;
743 } else if (version > PROTO_LAST) {
744 version = PROTO_LAST;
745 }
746
747 AString result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800748 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700749
Ray Essickf65f4212017-08-31 11:41:19 -0700750 if (version == PROTO_V0) {
751 result = "(";
752 } else {
753 snprintf(buffer, sizeof(buffer), "[%d:", version);
754 result.append(buffer);
755 }
756
Ray Essick3938dc62016-11-01 08:56:56 -0700757 // same order as we spill into the parcel, although not required
758 // key+session are our primary matching criteria
759 result.append(mKey.c_str());
760 result.append(":");
761 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
762 result.append(buffer);
763
Ray Essickf65f4212017-08-31 11:41:19 -0700764 snprintf(buffer, sizeof(buffer), "%d:", mUid);
765 result.append(buffer);
766
767 if (version >= PROTO_V1) {
768 result.append(mPkgName);
769 snprintf(buffer, sizeof(buffer), ":%d:", mPkgVersionCode);
770 result.append(buffer);
771 }
772
773 // in 'o' (v1) , the separator between pid and finalized was omitted
774 if (version <= PROTO_V0) {
775 snprintf(buffer, sizeof(buffer), "%d", mPid);
776 } else {
777 snprintf(buffer, sizeof(buffer), "%d:", mPid);
778 }
Ray Essick3938dc62016-11-01 08:56:56 -0700779 result.append(buffer);
780
781 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
782 result.append(buffer);
783 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
784 result.append(buffer);
785
786 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800787 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700788 snprintf(buffer, sizeof(buffer), "%d:", count);
789 result.append(buffer);
790 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800791 Prop *prop = &mProps[i];
792 switch (prop->mType) {
793 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700794 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800795 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700796 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800797 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700798 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800799 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700800 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800801 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700802 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800803 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700804 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800805 case MediaAnalyticsItem::kTypeRate:
806 snprintf(buffer,sizeof(buffer),
807 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
808 prop->u.rate.count, prop->u.rate.duration);
809 break;
810 case MediaAnalyticsItem::kTypeCString:
811 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700812 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800813 // XXX: sanitize string for ':' '='
814 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700815 buffer[0] = ':';
816 buffer[1] = '\0';
817 break;
818 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800819 ALOGE("to_String bad item type: %d for %s",
820 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700821 break;
822 }
823 result.append(buffer);
824 }
825
Ray Essickf65f4212017-08-31 11:41:19 -0700826 if (version == PROTO_V0) {
827 result.append(")");
828 } else {
829 result.append("]");
830 }
Ray Essick3938dc62016-11-01 08:56:56 -0700831
832 return result;
833}
834
835// for the lazy, we offer methods that finds the service and
836// calls the appropriate daemon
837bool MediaAnalyticsItem::selfrecord() {
838 return selfrecord(false);
839}
840
841bool MediaAnalyticsItem::selfrecord(bool forcenew) {
842
Ray Essickb5fac8e2016-12-12 11:33:56 -0800843 if (DEBUG_API) {
844 AString p = this->toString();
845 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
846 }
Ray Essick3938dc62016-11-01 08:56:56 -0700847
848 sp<IMediaAnalyticsService> svc = getInstance();
849
850 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700851 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
852 if (newid == SessionIDInvalid) {
853 AString p = this->toString();
854 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
855 return false;
856 }
Ray Essick3938dc62016-11-01 08:56:56 -0700857 return true;
858 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800859 AString p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700860 ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700861 return false;
862 }
863}
864
865// get a connection we can reuse for most of our lifetime
866// static
867sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
868static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700869static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700870
871//static
872bool MediaAnalyticsItem::isEnabled() {
873 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
874
875 if (enabled == -1) {
876 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
877 }
878 if (enabled == -1) {
879 enabled = MediaAnalyticsItem::EnabledProperty_default;
880 }
881 if (enabled <= 0) {
882 return false;
883 }
884 return true;
885}
886
Ray Essick2ab3c432017-10-02 09:29:49 -0700887
888// monitor health of our connection to the metrics service
889class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
890 virtual void binderDied(const wp<IBinder> &) {
891 ALOGW("Reacquire service connection on next request");
892 MediaAnalyticsItem::dropInstance();
893 }
894};
895
896static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
897
898// static
899void MediaAnalyticsItem::dropInstance() {
900 Mutex::Autolock _l(sInitMutex);
901 remainingBindAttempts = SVC_TRIES;
902 sAnalyticsService = NULL;
903}
904
Ray Essick3938dc62016-11-01 08:56:56 -0700905//static
906sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700907
Ray Essickd38e1742017-01-23 15:17:06 -0800908 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700909 int enabled = isEnabled();
910
911 if (enabled == false) {
912 if (DEBUG_SERVICEACCESS) {
913 ALOGD("disabled");
914 }
915 return NULL;
916 }
917
Ray Essick79a89ef2017-04-24 15:52:54 -0700918 // completely skip logging from certain UIDs. We do this here
919 // to avoid the multi-second timeouts while we learn that
920 // sepolicy will not let us find the service.
921 // We do this only for a select set of UIDs
922 // The sepolicy protection is still in place, we just want a faster
923 // response from this specific, small set of uids.
924 {
925 uid_t uid = getuid();
926 switch (uid) {
927 case AID_RADIO: // telephony subsystem, RIL
928 return NULL;
929 break;
930 default:
931 // let sepolicy deny access if appropriate
932 break;
933 }
934 }
935
Ray Essick3938dc62016-11-01 08:56:56 -0700936 {
937 Mutex::Autolock _l(sInitMutex);
938 const char *badness = "";
939
Ray Essick2ab3c432017-10-02 09:29:49 -0700940 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -0800941 // (1) we haven't tried to initialize it yet
942 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -0700943 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700944 sp<IServiceManager> sm = defaultServiceManager();
945 if (sm != NULL) {
946 sp<IBinder> binder = sm->getService(String16(servicename));
947 if (binder != NULL) {
948 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -0700949 if (sNotifier != NULL) {
950 sNotifier = NULL;
951 }
952 sNotifier = new MediaMetricsDeathNotifier();
953 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700954 } else {
955 badness = "did not find service";
956 }
957 } else {
958 badness = "No Service Manager access";
959 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800960
961 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700962 if (remainingBindAttempts > 0) {
963 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800964 }
965 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700966 ALOGD("Unable to bind to service %s: %s", servicename, badness);
967 }
968 }
969 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800970
Ray Essick3938dc62016-11-01 08:56:56 -0700971 return sAnalyticsService;
972 }
973}
974
Ray Essick3938dc62016-11-01 08:56:56 -0700975// merge the info from 'incoming' into this record.
976// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800977bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700978
979 // if I don't have key or session id, take them from incoming
980 // 'this' should never be missing both of them...
981 if (mKey.empty()) {
982 mKey = incoming->mKey;
983 } else if (mSessionID == 0) {
984 mSessionID = incoming->mSessionID;
985 }
986
987 // we always take the more recent 'finalized' value
988 setFinalized(incoming->getFinalized());
989
990 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800991 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700992 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800993 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800994 const char *p = iprop->mName;
995 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700996
997 // should ignore a zero length name...
998 if (len == 0) {
999 continue;
1000 }
1001
1002 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -07001003
Ray Essickb5fac8e2016-12-12 11:33:56 -08001004 if (oprop == NULL) {
1005 // no oprop, so we insert the new one
1006 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001007 if (oprop != NULL) {
1008 copyProp(oprop, iprop);
1009 } else {
1010 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -08001011 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001012 } else {
1013 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -07001014 }
1015 }
1016
1017 // not sure when we'd return false...
1018 return true;
1019}
1020
1021} // namespace android
1022