blob: 6b10713a23c265ee36ba6d8150ed63117526fa12 [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
103 for (size_t i = 0 ; i < mPropSize; i++ ) {
104 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) {
282 growProps();
283 // XXX: verify success
284 }
285 i = mPropCount++;
286 prop = &mProps[i];
287 prop->setName(name, len);
Ray Essickf65f4212017-08-31 11:41:19 -0700288 prop->mType = kTypeNone; // make caller set type info
Ray Essickb5fac8e2016-12-12 11:33:56 -0800289 }
290
291 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700292}
293
Ray Essickf65f4212017-08-31 11:41:19 -0700294// used within the summarizers; return whether property existed
295bool MediaAnalyticsItem::removeProp(const char *name) {
296 size_t len = strlen(name);
297 size_t i = findPropIndex(name, len);
298 if (i < mPropCount) {
299 Prop *prop = &mProps[i];
300 clearProp(prop);
301 if (i != mPropCount-1) {
302 // in the middle, bring last one down to fill gap
303 mProps[i] = mProps[mPropCount-1];
304 }
305 mPropCount--;
306 return true;
307 }
308 return false;
309}
310
Ray Essick3938dc62016-11-01 08:56:56 -0700311// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800312void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
313 Prop *prop = allocateProp(name);
314 prop->mType = kTypeInt32;
315 prop->u.int32Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700316}
317
Ray Essickb5fac8e2016-12-12 11:33:56 -0800318void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
319 Prop *prop = allocateProp(name);
320 prop->mType = kTypeInt64;
321 prop->u.int64Value = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700322}
323
Ray Essickb5fac8e2016-12-12 11:33:56 -0800324void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
325 Prop *prop = allocateProp(name);
326 prop->mType = kTypeDouble;
327 prop->u.doubleValue = value;
Ray Essick3938dc62016-11-01 08:56:56 -0700328}
329
Ray Essickb5fac8e2016-12-12 11:33:56 -0800330void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
331
332 Prop *prop = allocateProp(name);
333 // any old value will be gone
334 prop->mType = kTypeCString;
335 prop->u.CStringValue = strdup(value);
Ray Essick3938dc62016-11-01 08:56:56 -0700336}
337
Ray Essickb5fac8e2016-12-12 11:33:56 -0800338void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
339 Prop *prop = allocateProp(name);
340 prop->mType = kTypeRate;
341 prop->u.rate.count = count;
342 prop->u.rate.duration = duration;
343}
344
345
Ray Essick3938dc62016-11-01 08:56:56 -0700346// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800347void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
348 Prop *prop = allocateProp(name);
349 switch (prop->mType) {
350 case kTypeInt32:
351 prop->u.int32Value += value;
352 break;
353 default:
354 clearPropValue(prop);
355 prop->mType = kTypeInt32;
356 prop->u.int32Value = value;
357 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700358 }
Ray Essick3938dc62016-11-01 08:56:56 -0700359}
360
Ray Essickb5fac8e2016-12-12 11:33:56 -0800361void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
362 Prop *prop = allocateProp(name);
363 switch (prop->mType) {
364 case kTypeInt64:
365 prop->u.int64Value += value;
366 break;
367 default:
368 clearPropValue(prop);
369 prop->mType = kTypeInt64;
370 prop->u.int64Value = value;
371 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700372 }
Ray Essick3938dc62016-11-01 08:56:56 -0700373}
374
Ray Essickb5fac8e2016-12-12 11:33:56 -0800375void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
376 Prop *prop = allocateProp(name);
377 switch (prop->mType) {
378 case kTypeRate:
379 prop->u.rate.count += count;
380 prop->u.rate.duration += duration;
381 break;
382 default:
383 clearPropValue(prop);
384 prop->mType = kTypeRate;
385 prop->u.rate.count = count;
386 prop->u.rate.duration = duration;
387 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700388 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800389}
390
391void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
392 Prop *prop = allocateProp(name);
393 switch (prop->mType) {
394 case kTypeDouble:
395 prop->u.doubleValue += value;
396 break;
397 default:
398 clearPropValue(prop);
399 prop->mType = kTypeDouble;
400 prop->u.doubleValue = value;
401 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700402 }
Ray Essick3938dc62016-11-01 08:56:56 -0700403}
404
405// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800406bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
407 Prop *prop = findProp(name);
408 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700409 return false;
410 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800411 if (value != NULL) {
412 *value = prop->u.int32Value;
413 }
Ray Essick3938dc62016-11-01 08:56:56 -0700414 return true;
415}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800416
417bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
418 Prop *prop = findProp(name);
419 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700420 return false;
421 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800422 if (value != NULL) {
423 *value = prop->u.int64Value;
424 }
Ray Essick3938dc62016-11-01 08:56:56 -0700425 return true;
426}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800427
428bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
429 Prop *prop = findProp(name);
430 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700431 return false;
432 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800433 if (count != NULL) {
434 *count = prop->u.rate.count;
435 }
436 if (duration != NULL) {
437 *duration = prop->u.rate.duration;
438 }
439 if (rate != NULL) {
440 double r = 0.0;
441 if (prop->u.rate.duration != 0) {
442 r = prop->u.rate.count / (double) prop->u.rate.duration;
443 }
444 *rate = r;
445 }
446 return true;
447}
448
449bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
450 Prop *prop = findProp(name);
451 if (prop == NULL || prop->mType != kTypeDouble) {
452 return false;
453 }
454 if (value != NULL) {
455 *value = prop->u.doubleValue;
456 }
Ray Essick3938dc62016-11-01 08:56:56 -0700457 return true;
458}
459
460// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800461bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
462 Prop *prop = findProp(name);
463 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700464 return false;
465 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800466 if (value != NULL) {
467 *value = strdup(prop->u.CStringValue);
468 }
Ray Essick3938dc62016-11-01 08:56:56 -0700469 return true;
470}
471
472// remove indicated keys and their values
473// return value is # keys removed
474int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
475 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800476 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700477 return -1;
478 }
479 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800480 const char *name = attrs[i];
481 size_t len = strlen(name);
482 size_t j = findPropIndex(name, len);
483 if (j >= mPropCount) {
484 // not there
485 continue;
486 } else if (j+1 == mPropCount) {
487 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700488 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800489 clearProp(&mProps[j]);
490 mPropCount--;
491 } else {
492 // in the middle, bring last one down and shorten
493 zapped++;
494 clearProp(&mProps[j]);
495 mProps[j] = mProps[mPropCount-1];
496 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700497 }
498 }
499 return zapped;
500}
501
502// remove any keys NOT in the provided list
503// return value is # keys removed
504int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
505 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800506 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700507 return -1;
508 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800509 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
510 Prop *prop = &mProps[i];
511 for (ssize_t j = 0; j < n ; j++) {
512 if (strcmp(prop->mName, attrs[j]) == 0) {
513 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700514 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800515 if (i != (ssize_t)(mPropCount-1)) {
516 *prop = mProps[mPropCount-1];
517 }
518 initProp(&mProps[mPropCount-1]);
519 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700520 break;
521 }
522 }
523 }
524 return zapped;
525}
526
527// remove a single key
528// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800529int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
530 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700531}
532
Ray Essick3938dc62016-11-01 08:56:56 -0700533// handle individual items/properties stored within the class
534//
Ray Essick3938dc62016-11-01 08:56:56 -0700535
Ray Essickb5fac8e2016-12-12 11:33:56 -0800536void MediaAnalyticsItem::initProp(Prop *prop) {
537 if (prop != NULL) {
538 prop->mName = NULL;
539 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700540
Ray Essickb5fac8e2016-12-12 11:33:56 -0800541 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700542 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800543}
544
545void MediaAnalyticsItem::clearProp(Prop *prop)
546{
547 if (prop != NULL) {
548 if (prop->mName != NULL) {
549 free((void *)prop->mName);
550 prop->mName = NULL;
551 prop->mNameLen = 0;
552 }
553
554 clearPropValue(prop);
555 }
556}
557
558void MediaAnalyticsItem::clearPropValue(Prop *prop)
559{
560 if (prop != NULL) {
561 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
562 free(prop->u.CStringValue);
563 prop->u.CStringValue = NULL;
564 }
565 prop->mType = kTypeNone;
566 }
567}
568
569void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
570{
571 // get rid of any pointers in the dst
572 clearProp(dst);
573
574 *dst = *src;
575
576 // fix any pointers that we blindly copied, so we have our own copies
577 if (dst->mName) {
578 void *p = malloc(dst->mNameLen + 1);
579 memcpy (p, src->mName, dst->mNameLen + 1);
580 dst->mName = (const char *) p;
581 }
582 if (dst->mType == kTypeCString) {
583 dst->u.CStringValue = strdup(src->u.CStringValue);
584 }
585}
586
587void MediaAnalyticsItem::growProps(int increment)
588{
589 if (increment <= 0) {
590 increment = kGrowProps;
591 }
592 int nsize = mPropSize + increment;
593 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
594
595 if (ni != NULL) {
596 for (int i = mPropSize; i < nsize; i++) {
597 initProp(&ni[i]);
598 }
599 mProps = ni;
600 mPropSize = nsize;
601 }
Ray Essick3938dc62016-11-01 08:56:56 -0700602}
603
604// Parcel / serialize things for binder calls
605//
606
607int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
608 // into 'this' object
609 // .. we make a copy of the string to put away.
610 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700611 mPid = data.readInt32();
612 mUid = data.readInt32();
613 mPkgName = data.readCString();
614 mPkgVersionCode = data.readInt32();
Ray Essick3938dc62016-11-01 08:56:56 -0700615 mSessionID = data.readInt64();
616 mFinalized = data.readInt32();
617 mTimestamp = data.readInt64();
618
619 int count = data.readInt32();
620 for (int i = 0; i < count ; i++) {
621 MediaAnalyticsItem::Attr attr = data.readCString();
622 int32_t ztype = data.readInt32();
623 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800624 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700625 setInt32(attr, data.readInt32());
626 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800627 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700628 setInt64(attr, data.readInt64());
629 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800630 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700631 setDouble(attr, data.readDouble());
632 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800633 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700634 setCString(attr, data.readCString());
635 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800636 case MediaAnalyticsItem::kTypeRate:
637 {
638 int64_t count = data.readInt64();
639 int64_t duration = data.readInt64();
640 setRate(attr, count, duration);
641 }
642 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700643 default:
644 ALOGE("reading bad item type: %d, idx %d",
645 ztype, i);
646 return -1;
647 }
648 }
649
650 return 0;
651}
652
653int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
654 if (data == NULL) return -1;
655
656
657 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700658 data->writeInt32(mPid);
659 data->writeInt32(mUid);
660 data->writeCString(mPkgName.c_str());
661 data->writeInt32(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700662 data->writeInt64(mSessionID);
663 data->writeInt32(mFinalized);
664 data->writeInt64(mTimestamp);
665
666 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800667 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700668 data->writeInt32(count);
669 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800670 Prop *prop = &mProps[i];
671 data->writeCString(prop->mName);
672 data->writeInt32(prop->mType);
673 switch (prop->mType) {
674 case MediaAnalyticsItem::kTypeInt32:
675 data->writeInt32(prop->u.int32Value);
676 break;
677 case MediaAnalyticsItem::kTypeInt64:
678 data->writeInt64(prop->u.int64Value);
679 break;
680 case MediaAnalyticsItem::kTypeDouble:
681 data->writeDouble(prop->u.doubleValue);
682 break;
683 case MediaAnalyticsItem::kTypeRate:
684 data->writeInt64(prop->u.rate.count);
685 data->writeInt64(prop->u.rate.duration);
686 break;
687 case MediaAnalyticsItem::kTypeCString:
688 data->writeCString(prop->u.CStringValue);
689 break;
690 default:
691 ALOGE("found bad Prop type: %d, idx %d, name %s",
692 prop->mType, i, prop->mName);
693 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700694 }
695 }
696
697 return 0;
698}
699
700
Ray Essick3938dc62016-11-01 08:56:56 -0700701AString MediaAnalyticsItem::toString() {
Ray Essickf65f4212017-08-31 11:41:19 -0700702 return toString(-1);
703}
Ray Essick3938dc62016-11-01 08:56:56 -0700704
Ray Essickf65f4212017-08-31 11:41:19 -0700705AString MediaAnalyticsItem::toString(int version) {
706
707 // v0 : released with 'o'
708 // v1 : bug fix (missing pid/finalized separator),
709 // adds apk name, apk version code
710
711 if (version <= PROTO_FIRST) {
712 // default to original v0 format, until proper parsers are in place
713 version = PROTO_V0;
714 } else if (version > PROTO_LAST) {
715 version = PROTO_LAST;
716 }
717
718 AString result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800719 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700720
Ray Essickf65f4212017-08-31 11:41:19 -0700721 if (version == PROTO_V0) {
722 result = "(";
723 } else {
724 snprintf(buffer, sizeof(buffer), "[%d:", version);
725 result.append(buffer);
726 }
727
Ray Essick3938dc62016-11-01 08:56:56 -0700728 // same order as we spill into the parcel, although not required
729 // key+session are our primary matching criteria
730 result.append(mKey.c_str());
731 result.append(":");
732 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
733 result.append(buffer);
734
Ray Essickf65f4212017-08-31 11:41:19 -0700735 snprintf(buffer, sizeof(buffer), "%d:", mUid);
736 result.append(buffer);
737
738 if (version >= PROTO_V1) {
739 result.append(mPkgName);
740 snprintf(buffer, sizeof(buffer), ":%d:", mPkgVersionCode);
741 result.append(buffer);
742 }
743
744 // in 'o' (v1) , the separator between pid and finalized was omitted
745 if (version <= PROTO_V0) {
746 snprintf(buffer, sizeof(buffer), "%d", mPid);
747 } else {
748 snprintf(buffer, sizeof(buffer), "%d:", mPid);
749 }
Ray Essick3938dc62016-11-01 08:56:56 -0700750 result.append(buffer);
751
752 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
753 result.append(buffer);
754 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
755 result.append(buffer);
756
757 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800758 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700759 snprintf(buffer, sizeof(buffer), "%d:", count);
760 result.append(buffer);
761 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800762 Prop *prop = &mProps[i];
763 switch (prop->mType) {
764 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700765 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800766 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700767 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800768 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700769 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800770 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700771 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800772 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700773 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800774 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700775 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800776 case MediaAnalyticsItem::kTypeRate:
777 snprintf(buffer,sizeof(buffer),
778 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
779 prop->u.rate.count, prop->u.rate.duration);
780 break;
781 case MediaAnalyticsItem::kTypeCString:
782 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700783 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800784 // XXX: sanitize string for ':' '='
785 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700786 buffer[0] = ':';
787 buffer[1] = '\0';
788 break;
789 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800790 ALOGE("to_String bad item type: %d for %s",
791 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700792 break;
793 }
794 result.append(buffer);
795 }
796
Ray Essickf65f4212017-08-31 11:41:19 -0700797 if (version == PROTO_V0) {
798 result.append(")");
799 } else {
800 result.append("]");
801 }
Ray Essick3938dc62016-11-01 08:56:56 -0700802
803 return result;
804}
805
806// for the lazy, we offer methods that finds the service and
807// calls the appropriate daemon
808bool MediaAnalyticsItem::selfrecord() {
809 return selfrecord(false);
810}
811
812bool MediaAnalyticsItem::selfrecord(bool forcenew) {
813
Ray Essickb5fac8e2016-12-12 11:33:56 -0800814 if (DEBUG_API) {
815 AString p = this->toString();
816 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
817 }
Ray Essick3938dc62016-11-01 08:56:56 -0700818
819 sp<IMediaAnalyticsService> svc = getInstance();
820
821 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700822 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
823 if (newid == SessionIDInvalid) {
824 AString p = this->toString();
825 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
826 return false;
827 }
Ray Essick3938dc62016-11-01 08:56:56 -0700828 return true;
829 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800830 AString p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700831 ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700832 return false;
833 }
834}
835
836// get a connection we can reuse for most of our lifetime
837// static
838sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
839static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700840static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700841
842//static
843bool MediaAnalyticsItem::isEnabled() {
844 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
845
846 if (enabled == -1) {
847 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
848 }
849 if (enabled == -1) {
850 enabled = MediaAnalyticsItem::EnabledProperty_default;
851 }
852 if (enabled <= 0) {
853 return false;
854 }
855 return true;
856}
857
Ray Essick2ab3c432017-10-02 09:29:49 -0700858
859// monitor health of our connection to the metrics service
860class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
861 virtual void binderDied(const wp<IBinder> &) {
862 ALOGW("Reacquire service connection on next request");
863 MediaAnalyticsItem::dropInstance();
864 }
865};
866
867static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
868
869// static
870void MediaAnalyticsItem::dropInstance() {
871 Mutex::Autolock _l(sInitMutex);
872 remainingBindAttempts = SVC_TRIES;
873 sAnalyticsService = NULL;
874}
875
Ray Essick3938dc62016-11-01 08:56:56 -0700876//static
877sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700878
Ray Essickd38e1742017-01-23 15:17:06 -0800879 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700880 int enabled = isEnabled();
881
882 if (enabled == false) {
883 if (DEBUG_SERVICEACCESS) {
884 ALOGD("disabled");
885 }
886 return NULL;
887 }
888
Ray Essick79a89ef2017-04-24 15:52:54 -0700889 // completely skip logging from certain UIDs. We do this here
890 // to avoid the multi-second timeouts while we learn that
891 // sepolicy will not let us find the service.
892 // We do this only for a select set of UIDs
893 // The sepolicy protection is still in place, we just want a faster
894 // response from this specific, small set of uids.
895 {
896 uid_t uid = getuid();
897 switch (uid) {
898 case AID_RADIO: // telephony subsystem, RIL
899 return NULL;
900 break;
901 default:
902 // let sepolicy deny access if appropriate
903 break;
904 }
905 }
906
Ray Essick3938dc62016-11-01 08:56:56 -0700907 {
908 Mutex::Autolock _l(sInitMutex);
909 const char *badness = "";
910
Ray Essick2ab3c432017-10-02 09:29:49 -0700911 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -0800912 // (1) we haven't tried to initialize it yet
913 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -0700914 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700915 sp<IServiceManager> sm = defaultServiceManager();
916 if (sm != NULL) {
917 sp<IBinder> binder = sm->getService(String16(servicename));
918 if (binder != NULL) {
919 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -0700920 if (sNotifier != NULL) {
921 sNotifier = NULL;
922 }
923 sNotifier = new MediaMetricsDeathNotifier();
924 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700925 } else {
926 badness = "did not find service";
927 }
928 } else {
929 badness = "No Service Manager access";
930 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800931
932 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700933 if (remainingBindAttempts > 0) {
934 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800935 }
936 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700937 ALOGD("Unable to bind to service %s: %s", servicename, badness);
938 }
939 }
940 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800941
Ray Essick3938dc62016-11-01 08:56:56 -0700942 return sAnalyticsService;
943 }
944}
945
Ray Essick3938dc62016-11-01 08:56:56 -0700946// merge the info from 'incoming' into this record.
947// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800948bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700949
950 // if I don't have key or session id, take them from incoming
951 // 'this' should never be missing both of them...
952 if (mKey.empty()) {
953 mKey = incoming->mKey;
954 } else if (mSessionID == 0) {
955 mSessionID = incoming->mSessionID;
956 }
957
958 // we always take the more recent 'finalized' value
959 setFinalized(incoming->getFinalized());
960
961 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800962 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700963 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800964 Prop *iprop = &incoming->mProps[i];
965 Prop *oprop = findProp(iprop->mName);
966 const char *p = iprop->mName;
967 size_t len = strlen(p);
968 char semantic = p[len-1];
Ray Essick3938dc62016-11-01 08:56:56 -0700969
Ray Essickb5fac8e2016-12-12 11:33:56 -0800970 if (oprop == NULL) {
971 // no oprop, so we insert the new one
972 oprop = allocateProp(p);
973 copyProp(oprop, iprop);
974 } else {
975 // merge iprop into oprop
976 switch (semantic) {
977 case '<': // first aka keep old)
978 /* nop */
979 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700980
Ray Essickb5fac8e2016-12-12 11:33:56 -0800981 default: // default is 'last'
982 case '>': // last (aka keep new)
983 copyProp(oprop, iprop);
984 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700985
Ray Essickb5fac8e2016-12-12 11:33:56 -0800986 case '+': /* sum */
987 // XXX validate numeric types, sum in place
988 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700989
Ray Essickb5fac8e2016-12-12 11:33:56 -0800990 }
Ray Essick3938dc62016-11-01 08:56:56 -0700991 }
992 }
993
994 // not sure when we'd return false...
995 return true;
996}
997
998} // namespace android
999