blob: dc2bec847f8799e722674bde2d4c202da6e90ddf [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
Ray Essick3938dc62016-11-01 08:56:56 -070032#include <binder/IServiceManager.h>
33#include <media/IMediaAnalyticsService.h>
34#include <media/MediaAnalyticsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070035#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070036
37namespace android {
38
39#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080040#define DEBUG_API 0
41#define DEBUG_ALLOCATIONS 0
42
43// after this many failed attempts, we stop trying [from this process] and just say that
44// the service is off.
45#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070046
47// the few universal keys we have
48const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
49const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
50
Ray Essickd38e1742017-01-23 15:17:06 -080051const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
52const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
Ray Essickd6a6c672017-01-25 14:28:51 -080053const int MediaAnalyticsItem::EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -070054
55
56// access functions for the class
57MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080058 : mPid(-1),
59 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070060 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070061 mSessionID(MediaAnalyticsItem::SessionIDNone),
62 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080063 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080064 mPropCount(0), mPropSize(0), mProps(NULL)
65{
Ray Essick3938dc62016-11-01 08:56:56 -070066 mKey = MediaAnalyticsItem::kKeyNone;
67}
68
69MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080070 : mPid(-1),
71 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070072 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070073 mSessionID(MediaAnalyticsItem::SessionIDNone),
74 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080075 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080076 mPropCount(0), mPropSize(0), mProps(NULL)
77{
78 if (DEBUG_ALLOCATIONS) {
79 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
80 }
Ray Essick3938dc62016-11-01 08:56:56 -070081 mKey = key;
82}
83
84MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080085 if (DEBUG_ALLOCATIONS) {
86 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
87 }
Ray Essick3938dc62016-11-01 08:56:56 -070088 clear();
89}
90
Ray Essickb5fac8e2016-12-12 11:33:56 -080091void MediaAnalyticsItem::clear() {
92
93 // clean allocated storage from key
94 mKey.clear();
95
Ray Essickd38e1742017-01-23 15:17:06 -080096 // clean various major parameters
97 mSessionID = MediaAnalyticsItem::SessionIDNone;
98
Ray Essickb5fac8e2016-12-12 11:33:56 -080099 // clean attributes
100 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700101 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800102 clearProp(&mProps[i]);
103 }
104 // the attribute records themselves
105 if (mProps != NULL) {
106 free(mProps);
107 mProps = NULL;
108 }
109 mPropSize = 0;
110 mPropCount = 0;
111
112 return;
113}
114
115// make a deep copy of myself
116MediaAnalyticsItem *MediaAnalyticsItem::dup() {
117 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
118
119 if (dst != NULL) {
120 // key as part of constructor
121 dst->mPid = this->mPid;
122 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700123 dst->mPkgName = this->mPkgName;
124 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800125 dst->mSessionID = this->mSessionID;
126 dst->mTimestamp = this->mTimestamp;
127 dst->mFinalized = this->mFinalized;
128
129 // properties aka attributes
130 dst->growProps(this->mPropCount);
131 for(size_t i=0;i<mPropCount;i++) {
132 copyProp(&dst->mProps[i], &this->mProps[i]);
133 }
134 dst->mPropCount = this->mPropCount;
135 }
136
137 return dst;
138}
139
Ray Essick3938dc62016-11-01 08:56:56 -0700140MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
141 mSessionID = id;
142 return *this;
143}
144
145MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
146 return mSessionID;
147}
148
149MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700150
151 if (mSessionID == SessionIDNone) {
152 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800153 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700154 sp<IMediaAnalyticsService> svc = getInstance();
155 if (svc != NULL) {
156 newid = svc->generateUniqueSessionID();
157 }
158 mSessionID = newid;
159 }
160
161 return mSessionID;
162}
163
164MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
165 mSessionID = MediaAnalyticsItem::SessionIDNone;
166 return *this;
167}
168
169MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
170 mTimestamp = ts;
171 return *this;
172}
173
174nsecs_t MediaAnalyticsItem::getTimestamp() const {
175 return mTimestamp;
176}
177
178MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
179 mPid = pid;
180 return *this;
181}
182
183pid_t MediaAnalyticsItem::getPid() const {
184 return mPid;
185}
186
187MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
188 mUid = uid;
189 return *this;
190}
191
192uid_t MediaAnalyticsItem::getUid() const {
193 return mUid;
194}
195
Ray Essick783bd0d2018-01-11 11:10:35 -0800196MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700197 mPkgName = pkgName;
198 return *this;
199}
200
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800201MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700202 mPkgVersionCode = pkgVersionCode;
203 return *this;
204}
205
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800206int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700207 return mPkgVersionCode;
208}
209
Ray Essickb5fac8e2016-12-12 11:33:56 -0800210// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700211MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700212 mKey = key;
213 return *this;
214}
215
216MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
217 return mKey;
218}
219
Ray Essickb5fac8e2016-12-12 11:33:56 -0800220// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700221int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800222 return mPropCount;
223}
224
225// find the proper entry in the list
226size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
227{
228 size_t i = 0;
229 for (; i < mPropCount; i++) {
230 Prop *prop = &mProps[i];
231 if (prop->mNameLen != len) {
232 continue;
233 }
234 if (memcmp(name, prop->mName, len) == 0) {
235 break;
236 }
237 }
238 return i;
239}
240
241MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
242 size_t len = strlen(name);
243 size_t i = findPropIndex(name, len);
244 if (i < mPropCount) {
245 return &mProps[i];
246 }
247 return NULL;
248}
249
250void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
251 mNameLen = len;
252 mName = (const char *) malloc(len+1);
253 memcpy ((void *)mName, name, len+1);
254}
255
256// used only as part of a storing operation
257MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
258 size_t len = strlen(name);
259 size_t i = findPropIndex(name, len);
260 Prop *prop;
261
262 if (i < mPropCount) {
263 prop = &mProps[i];
264 } else {
265 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700266 if (growProps() == false) {
267 ALOGE("failed allocation for new props");
268 return NULL;
269 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800270 }
271 i = mPropCount++;
272 prop = &mProps[i];
273 prop->setName(name, len);
Ray Essickf65f4212017-08-31 11:41:19 -0700274 prop->mType = kTypeNone; // make caller set type info
Ray Essickb5fac8e2016-12-12 11:33:56 -0800275 }
276
277 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700278}
279
Ray Essickf65f4212017-08-31 11:41:19 -0700280// used within the summarizers; return whether property existed
281bool MediaAnalyticsItem::removeProp(const char *name) {
282 size_t len = strlen(name);
283 size_t i = findPropIndex(name, len);
284 if (i < mPropCount) {
285 Prop *prop = &mProps[i];
286 clearProp(prop);
287 if (i != mPropCount-1) {
288 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700289 copyProp(prop, &mProps[mPropCount-1]);
290 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700291 }
292 mPropCount--;
293 return true;
294 }
295 return false;
296}
297
Ray Essick3938dc62016-11-01 08:56:56 -0700298// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800299void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
300 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700301 if (prop != NULL) {
302 prop->mType = kTypeInt32;
303 prop->u.int32Value = value;
304 }
Ray Essick3938dc62016-11-01 08:56:56 -0700305}
306
Ray Essickb5fac8e2016-12-12 11:33:56 -0800307void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
308 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700309 if (prop != NULL) {
310 prop->mType = kTypeInt64;
311 prop->u.int64Value = value;
312 }
Ray Essick3938dc62016-11-01 08:56:56 -0700313}
314
Ray Essickb5fac8e2016-12-12 11:33:56 -0800315void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
316 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700317 if (prop != NULL) {
318 prop->mType = kTypeDouble;
319 prop->u.doubleValue = value;
320 }
Ray Essick3938dc62016-11-01 08:56:56 -0700321}
322
Ray Essickb5fac8e2016-12-12 11:33:56 -0800323void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
324
325 Prop *prop = allocateProp(name);
326 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700327 if (prop != NULL) {
328 prop->mType = kTypeCString;
329 prop->u.CStringValue = strdup(value);
330 }
Ray Essick3938dc62016-11-01 08:56:56 -0700331}
332
Ray Essickb5fac8e2016-12-12 11:33:56 -0800333void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
334 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700335 if (prop != NULL) {
336 prop->mType = kTypeRate;
337 prop->u.rate.count = count;
338 prop->u.rate.duration = duration;
339 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800340}
341
342
Ray Essick3938dc62016-11-01 08:56:56 -0700343// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800344void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
345 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700346 if (prop == NULL) {
347 return;
348 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800349 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);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700363 if (prop == NULL) {
364 return;
365 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800366 switch (prop->mType) {
367 case kTypeInt64:
368 prop->u.int64Value += value;
369 break;
370 default:
371 clearPropValue(prop);
372 prop->mType = kTypeInt64;
373 prop->u.int64Value = value;
374 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700375 }
Ray Essick3938dc62016-11-01 08:56:56 -0700376}
377
Ray Essickb5fac8e2016-12-12 11:33:56 -0800378void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
379 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700380 if (prop == NULL) {
381 return;
382 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800383 switch (prop->mType) {
384 case kTypeRate:
385 prop->u.rate.count += count;
386 prop->u.rate.duration += duration;
387 break;
388 default:
389 clearPropValue(prop);
390 prop->mType = kTypeRate;
391 prop->u.rate.count = count;
392 prop->u.rate.duration = duration;
393 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700394 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800395}
396
397void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
398 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700399 if (prop == NULL) {
400 return;
401 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800402 switch (prop->mType) {
403 case kTypeDouble:
404 prop->u.doubleValue += value;
405 break;
406 default:
407 clearPropValue(prop);
408 prop->mType = kTypeDouble;
409 prop->u.doubleValue = value;
410 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700411 }
Ray Essick3938dc62016-11-01 08:56:56 -0700412}
413
414// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800415bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
416 Prop *prop = findProp(name);
417 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700418 return false;
419 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800420 if (value != NULL) {
421 *value = prop->u.int32Value;
422 }
Ray Essick3938dc62016-11-01 08:56:56 -0700423 return true;
424}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800425
426bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
427 Prop *prop = findProp(name);
428 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700429 return false;
430 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800431 if (value != NULL) {
432 *value = prop->u.int64Value;
433 }
Ray Essick3938dc62016-11-01 08:56:56 -0700434 return true;
435}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800436
437bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
438 Prop *prop = findProp(name);
439 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700440 return false;
441 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800442 if (count != NULL) {
443 *count = prop->u.rate.count;
444 }
445 if (duration != NULL) {
446 *duration = prop->u.rate.duration;
447 }
448 if (rate != NULL) {
449 double r = 0.0;
450 if (prop->u.rate.duration != 0) {
451 r = prop->u.rate.count / (double) prop->u.rate.duration;
452 }
453 *rate = r;
454 }
455 return true;
456}
457
458bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
459 Prop *prop = findProp(name);
460 if (prop == NULL || prop->mType != kTypeDouble) {
461 return false;
462 }
463 if (value != NULL) {
464 *value = prop->u.doubleValue;
465 }
Ray Essick3938dc62016-11-01 08:56:56 -0700466 return true;
467}
468
469// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800470bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
471 Prop *prop = findProp(name);
472 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700473 return false;
474 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800475 if (value != NULL) {
476 *value = strdup(prop->u.CStringValue);
477 }
Ray Essick3938dc62016-11-01 08:56:56 -0700478 return true;
479}
480
481// remove indicated keys and their values
482// return value is # keys removed
483int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
484 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800485 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700486 return -1;
487 }
488 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800489 const char *name = attrs[i];
490 size_t len = strlen(name);
491 size_t j = findPropIndex(name, len);
492 if (j >= mPropCount) {
493 // not there
494 continue;
495 } else if (j+1 == mPropCount) {
496 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700497 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800498 clearProp(&mProps[j]);
499 mPropCount--;
500 } else {
501 // in the middle, bring last one down and shorten
502 zapped++;
503 clearProp(&mProps[j]);
504 mProps[j] = mProps[mPropCount-1];
505 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700506 }
507 }
508 return zapped;
509}
510
511// remove any keys NOT in the provided list
512// return value is # keys removed
513int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
514 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800515 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700516 return -1;
517 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800518 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
519 Prop *prop = &mProps[i];
520 for (ssize_t j = 0; j < n ; j++) {
521 if (strcmp(prop->mName, attrs[j]) == 0) {
522 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700523 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800524 if (i != (ssize_t)(mPropCount-1)) {
525 *prop = mProps[mPropCount-1];
526 }
527 initProp(&mProps[mPropCount-1]);
528 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700529 break;
530 }
531 }
532 }
533 return zapped;
534}
535
536// remove a single key
537// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800538int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
539 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700540}
541
Ray Essick3938dc62016-11-01 08:56:56 -0700542// handle individual items/properties stored within the class
543//
Ray Essick3938dc62016-11-01 08:56:56 -0700544
Ray Essickb5fac8e2016-12-12 11:33:56 -0800545void MediaAnalyticsItem::initProp(Prop *prop) {
546 if (prop != NULL) {
547 prop->mName = NULL;
548 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700549
Ray Essickb5fac8e2016-12-12 11:33:56 -0800550 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700551 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800552}
553
554void MediaAnalyticsItem::clearProp(Prop *prop)
555{
556 if (prop != NULL) {
557 if (prop->mName != NULL) {
558 free((void *)prop->mName);
559 prop->mName = NULL;
560 prop->mNameLen = 0;
561 }
562
563 clearPropValue(prop);
564 }
565}
566
567void MediaAnalyticsItem::clearPropValue(Prop *prop)
568{
569 if (prop != NULL) {
570 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
571 free(prop->u.CStringValue);
572 prop->u.CStringValue = NULL;
573 }
574 prop->mType = kTypeNone;
575 }
576}
577
578void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
579{
580 // get rid of any pointers in the dst
581 clearProp(dst);
582
583 *dst = *src;
584
585 // fix any pointers that we blindly copied, so we have our own copies
586 if (dst->mName) {
587 void *p = malloc(dst->mNameLen + 1);
588 memcpy (p, src->mName, dst->mNameLen + 1);
589 dst->mName = (const char *) p;
590 }
591 if (dst->mType == kTypeCString) {
592 dst->u.CStringValue = strdup(src->u.CStringValue);
593 }
594}
595
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700596bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800597{
598 if (increment <= 0) {
599 increment = kGrowProps;
600 }
601 int nsize = mPropSize + increment;
602 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
603
604 if (ni != NULL) {
605 for (int i = mPropSize; i < nsize; i++) {
606 initProp(&ni[i]);
607 }
608 mProps = ni;
609 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700610 return true;
611 } else {
612 ALOGW("MediaAnalyticsItem::growProps fails");
613 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800614 }
Ray Essick3938dc62016-11-01 08:56:56 -0700615}
616
617// Parcel / serialize things for binder calls
618//
619
620int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
621 // into 'this' object
622 // .. we make a copy of the string to put away.
623 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700624 mPid = data.readInt32();
625 mUid = data.readInt32();
626 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800627 mPkgVersionCode = data.readInt64();
Ray Essick3938dc62016-11-01 08:56:56 -0700628 mSessionID = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800629 // We no longer pay attention to user setting of finalized, BUT it's
630 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700631 mFinalized = data.readInt32();
Ray Essick92d23b42018-01-29 12:10:30 -0800632 mFinalized = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700633 mTimestamp = data.readInt64();
634
635 int count = data.readInt32();
636 for (int i = 0; i < count ; i++) {
637 MediaAnalyticsItem::Attr attr = data.readCString();
638 int32_t ztype = data.readInt32();
639 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800640 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700641 setInt32(attr, data.readInt32());
642 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800643 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700644 setInt64(attr, data.readInt64());
645 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800646 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700647 setDouble(attr, data.readDouble());
648 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800649 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700650 setCString(attr, data.readCString());
651 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800652 case MediaAnalyticsItem::kTypeRate:
653 {
654 int64_t count = data.readInt64();
655 int64_t duration = data.readInt64();
656 setRate(attr, count, duration);
657 }
658 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700659 default:
660 ALOGE("reading bad item type: %d, idx %d",
661 ztype, i);
662 return -1;
663 }
664 }
665
666 return 0;
667}
668
669int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
670 if (data == NULL) return -1;
671
672
673 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700674 data->writeInt32(mPid);
675 data->writeInt32(mUid);
676 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800677 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700678 data->writeInt64(mSessionID);
679 data->writeInt32(mFinalized);
680 data->writeInt64(mTimestamp);
681
682 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800683 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700684 data->writeInt32(count);
685 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800686 Prop *prop = &mProps[i];
687 data->writeCString(prop->mName);
688 data->writeInt32(prop->mType);
689 switch (prop->mType) {
690 case MediaAnalyticsItem::kTypeInt32:
691 data->writeInt32(prop->u.int32Value);
692 break;
693 case MediaAnalyticsItem::kTypeInt64:
694 data->writeInt64(prop->u.int64Value);
695 break;
696 case MediaAnalyticsItem::kTypeDouble:
697 data->writeDouble(prop->u.doubleValue);
698 break;
699 case MediaAnalyticsItem::kTypeRate:
700 data->writeInt64(prop->u.rate.count);
701 data->writeInt64(prop->u.rate.duration);
702 break;
703 case MediaAnalyticsItem::kTypeCString:
704 data->writeCString(prop->u.CStringValue);
705 break;
706 default:
707 ALOGE("found bad Prop type: %d, idx %d, name %s",
708 prop->mType, i, prop->mName);
709 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700710 }
711 }
712
713 return 0;
714}
715
716
Ray Essick783bd0d2018-01-11 11:10:35 -0800717std::string MediaAnalyticsItem::toString() {
Ray Essick5b77bd22018-01-23 16:11:06 -0800718 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700719}
Ray Essick3938dc62016-11-01 08:56:56 -0700720
Ray Essick783bd0d2018-01-11 11:10:35 -0800721std::string MediaAnalyticsItem::toString(int version) {
Ray Essickf65f4212017-08-31 11:41:19 -0700722
723 // v0 : released with 'o'
724 // v1 : bug fix (missing pid/finalized separator),
725 // adds apk name, apk version code
726
727 if (version <= PROTO_FIRST) {
728 // default to original v0 format, until proper parsers are in place
729 version = PROTO_V0;
730 } else if (version > PROTO_LAST) {
731 version = PROTO_LAST;
732 }
733
Ray Essick783bd0d2018-01-11 11:10:35 -0800734 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800735 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700736
Ray Essickf65f4212017-08-31 11:41:19 -0700737 if (version == PROTO_V0) {
738 result = "(";
739 } else {
740 snprintf(buffer, sizeof(buffer), "[%d:", version);
741 result.append(buffer);
742 }
743
Ray Essick3938dc62016-11-01 08:56:56 -0700744 // same order as we spill into the parcel, although not required
745 // key+session are our primary matching criteria
746 result.append(mKey.c_str());
747 result.append(":");
748 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
749 result.append(buffer);
750
Ray Essickf65f4212017-08-31 11:41:19 -0700751 snprintf(buffer, sizeof(buffer), "%d:", mUid);
752 result.append(buffer);
753
754 if (version >= PROTO_V1) {
755 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800756 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700757 result.append(buffer);
758 }
759
760 // in 'o' (v1) , the separator between pid and finalized was omitted
761 if (version <= PROTO_V0) {
762 snprintf(buffer, sizeof(buffer), "%d", mPid);
763 } else {
764 snprintf(buffer, sizeof(buffer), "%d:", mPid);
765 }
Ray Essick3938dc62016-11-01 08:56:56 -0700766 result.append(buffer);
767
768 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
769 result.append(buffer);
770 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
771 result.append(buffer);
772
773 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800774 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700775 snprintf(buffer, sizeof(buffer), "%d:", count);
776 result.append(buffer);
777 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800778 Prop *prop = &mProps[i];
779 switch (prop->mType) {
780 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700781 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800782 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700783 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800784 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700785 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800786 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700787 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800788 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700789 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800790 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700791 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800792 case MediaAnalyticsItem::kTypeRate:
793 snprintf(buffer,sizeof(buffer),
794 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
795 prop->u.rate.count, prop->u.rate.duration);
796 break;
797 case MediaAnalyticsItem::kTypeCString:
798 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700799 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800800 // XXX: sanitize string for ':' '='
801 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700802 buffer[0] = ':';
803 buffer[1] = '\0';
804 break;
805 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800806 ALOGE("to_String bad item type: %d for %s",
807 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700808 break;
809 }
810 result.append(buffer);
811 }
812
Ray Essickf65f4212017-08-31 11:41:19 -0700813 if (version == PROTO_V0) {
814 result.append(")");
815 } else {
816 result.append("]");
817 }
Ray Essick3938dc62016-11-01 08:56:56 -0700818
819 return result;
820}
821
822// for the lazy, we offer methods that finds the service and
823// calls the appropriate daemon
824bool MediaAnalyticsItem::selfrecord() {
825 return selfrecord(false);
826}
827
828bool MediaAnalyticsItem::selfrecord(bool forcenew) {
829
Ray Essickb5fac8e2016-12-12 11:33:56 -0800830 if (DEBUG_API) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800831 std::string p = this->toString();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800832 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
833 }
Ray Essick3938dc62016-11-01 08:56:56 -0700834
835 sp<IMediaAnalyticsService> svc = getInstance();
836
837 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700838 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
839 if (newid == SessionIDInvalid) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800840 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700841 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
842 return false;
843 }
Ray Essick3938dc62016-11-01 08:56:56 -0700844 return true;
845 } else {
Ray Essick783bd0d2018-01-11 11:10:35 -0800846 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700847 ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700848 return false;
849 }
850}
851
852// get a connection we can reuse for most of our lifetime
853// static
854sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
855static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700856static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700857
858//static
859bool MediaAnalyticsItem::isEnabled() {
860 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
861
862 if (enabled == -1) {
863 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
864 }
865 if (enabled == -1) {
866 enabled = MediaAnalyticsItem::EnabledProperty_default;
867 }
868 if (enabled <= 0) {
869 return false;
870 }
871 return true;
872}
873
Ray Essick2ab3c432017-10-02 09:29:49 -0700874
875// monitor health of our connection to the metrics service
876class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
877 virtual void binderDied(const wp<IBinder> &) {
878 ALOGW("Reacquire service connection on next request");
879 MediaAnalyticsItem::dropInstance();
880 }
881};
882
883static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
884
885// static
886void MediaAnalyticsItem::dropInstance() {
887 Mutex::Autolock _l(sInitMutex);
888 remainingBindAttempts = SVC_TRIES;
889 sAnalyticsService = NULL;
890}
891
Ray Essick3938dc62016-11-01 08:56:56 -0700892//static
893sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700894
Ray Essickd38e1742017-01-23 15:17:06 -0800895 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700896 int enabled = isEnabled();
897
898 if (enabled == false) {
899 if (DEBUG_SERVICEACCESS) {
900 ALOGD("disabled");
901 }
902 return NULL;
903 }
904
Ray Essick79a89ef2017-04-24 15:52:54 -0700905 // completely skip logging from certain UIDs. We do this here
906 // to avoid the multi-second timeouts while we learn that
907 // sepolicy will not let us find the service.
908 // We do this only for a select set of UIDs
909 // The sepolicy protection is still in place, we just want a faster
910 // response from this specific, small set of uids.
911 {
912 uid_t uid = getuid();
913 switch (uid) {
914 case AID_RADIO: // telephony subsystem, RIL
915 return NULL;
916 break;
917 default:
918 // let sepolicy deny access if appropriate
919 break;
920 }
921 }
922
Ray Essick3938dc62016-11-01 08:56:56 -0700923 {
924 Mutex::Autolock _l(sInitMutex);
925 const char *badness = "";
926
Ray Essick2ab3c432017-10-02 09:29:49 -0700927 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -0800928 // (1) we haven't tried to initialize it yet
929 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -0700930 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700931 sp<IServiceManager> sm = defaultServiceManager();
932 if (sm != NULL) {
933 sp<IBinder> binder = sm->getService(String16(servicename));
934 if (binder != NULL) {
935 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -0700936 if (sNotifier != NULL) {
937 sNotifier = NULL;
938 }
939 sNotifier = new MediaMetricsDeathNotifier();
940 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700941 } else {
942 badness = "did not find service";
943 }
944 } else {
945 badness = "No Service Manager access";
946 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800947
948 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700949 if (remainingBindAttempts > 0) {
950 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800951 }
952 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700953 ALOGD("Unable to bind to service %s: %s", servicename, badness);
954 }
955 }
956 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800957
Ray Essick3938dc62016-11-01 08:56:56 -0700958 return sAnalyticsService;
959 }
960}
961
Ray Essick3938dc62016-11-01 08:56:56 -0700962// merge the info from 'incoming' into this record.
963// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800964bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700965
966 // if I don't have key or session id, take them from incoming
967 // 'this' should never be missing both of them...
968 if (mKey.empty()) {
969 mKey = incoming->mKey;
970 } else if (mSessionID == 0) {
971 mSessionID = incoming->mSessionID;
972 }
973
Ray Essick3938dc62016-11-01 08:56:56 -0700974 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800975 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700976 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800977 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800978 const char *p = iprop->mName;
979 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700980
981 // should ignore a zero length name...
982 if (len == 0) {
983 continue;
984 }
985
986 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700987
Ray Essickb5fac8e2016-12-12 11:33:56 -0800988 if (oprop == NULL) {
989 // no oprop, so we insert the new one
990 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700991 if (oprop != NULL) {
992 copyProp(oprop, iprop);
993 } else {
994 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800995 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700996 } else {
997 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -0700998 }
999 }
1000
1001 // not sure when we'd return false...
1002 return true;
1003}
1004
1005} // namespace android
1006