blob: 423dfb820743c8c5f9a1b0208e6950971e7595a1 [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 Essickb5fac8e2016-12-12 11:33:56 -080063 mFinalized(0),
64 mPropCount(0), mPropSize(0), mProps(NULL)
65{
Ray Essick3938dc62016-11-01 08:56:56 -070066 mKey = MediaAnalyticsItem::kKeyNone;
67}
68
69MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080070 : mPid(-1),
71 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070072 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070073 mSessionID(MediaAnalyticsItem::SessionIDNone),
74 mTimestamp(0),
Ray Essickb5fac8e2016-12-12 11:33:56 -080075 mFinalized(0),
76 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 -0700140// so clients can send intermediate values to be overlaid later
141MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
142 mFinalized = value;
143 return *this;
144}
145
146bool MediaAnalyticsItem::getFinalized() const {
147 return mFinalized;
148}
149
150MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
151 mSessionID = id;
152 return *this;
153}
154
155MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
156 return mSessionID;
157}
158
159MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700160
161 if (mSessionID == SessionIDNone) {
162 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800163 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700164 sp<IMediaAnalyticsService> svc = getInstance();
165 if (svc != NULL) {
166 newid = svc->generateUniqueSessionID();
167 }
168 mSessionID = newid;
169 }
170
171 return mSessionID;
172}
173
174MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
175 mSessionID = MediaAnalyticsItem::SessionIDNone;
176 return *this;
177}
178
179MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
180 mTimestamp = ts;
181 return *this;
182}
183
184nsecs_t MediaAnalyticsItem::getTimestamp() const {
185 return mTimestamp;
186}
187
188MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
189 mPid = pid;
190 return *this;
191}
192
193pid_t MediaAnalyticsItem::getPid() const {
194 return mPid;
195}
196
197MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
198 mUid = uid;
199 return *this;
200}
201
202uid_t MediaAnalyticsItem::getUid() const {
203 return mUid;
204}
205
Ray Essick783bd0d2018-01-11 11:10:35 -0800206MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700207 mPkgName = pkgName;
208 return *this;
209}
210
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800211MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700212 mPkgVersionCode = pkgVersionCode;
213 return *this;
214}
215
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800216int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700217 return mPkgVersionCode;
218}
219
Ray Essickb5fac8e2016-12-12 11:33:56 -0800220// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700221MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700222 mKey = key;
223 return *this;
224}
225
226MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
227 return mKey;
228}
229
Ray Essickb5fac8e2016-12-12 11:33:56 -0800230// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700231int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800232 return mPropCount;
233}
234
235// find the proper entry in the list
236size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
237{
238 size_t i = 0;
239 for (; i < mPropCount; i++) {
240 Prop *prop = &mProps[i];
241 if (prop->mNameLen != len) {
242 continue;
243 }
244 if (memcmp(name, prop->mName, len) == 0) {
245 break;
246 }
247 }
248 return i;
249}
250
251MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
252 size_t len = strlen(name);
253 size_t i = findPropIndex(name, len);
254 if (i < mPropCount) {
255 return &mProps[i];
256 }
257 return NULL;
258}
259
260void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
261 mNameLen = len;
262 mName = (const char *) malloc(len+1);
263 memcpy ((void *)mName, name, len+1);
264}
265
266// used only as part of a storing operation
267MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
268 size_t len = strlen(name);
269 size_t i = findPropIndex(name, len);
270 Prop *prop;
271
272 if (i < mPropCount) {
273 prop = &mProps[i];
274 } else {
275 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700276 if (growProps() == false) {
277 ALOGE("failed allocation for new props");
278 return NULL;
279 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800280 }
281 i = mPropCount++;
282 prop = &mProps[i];
283 prop->setName(name, len);
Ray Essickf65f4212017-08-31 11:41:19 -0700284 prop->mType = kTypeNone; // make caller set type info
Ray Essickb5fac8e2016-12-12 11:33:56 -0800285 }
286
287 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700288}
289
Ray Essickf65f4212017-08-31 11:41:19 -0700290// used within the summarizers; return whether property existed
291bool MediaAnalyticsItem::removeProp(const char *name) {
292 size_t len = strlen(name);
293 size_t i = findPropIndex(name, len);
294 if (i < mPropCount) {
295 Prop *prop = &mProps[i];
296 clearProp(prop);
297 if (i != mPropCount-1) {
298 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700299 copyProp(prop, &mProps[mPropCount-1]);
300 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700301 }
302 mPropCount--;
303 return true;
304 }
305 return false;
306}
307
Ray Essick3938dc62016-11-01 08:56:56 -0700308// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800309void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
310 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700311 if (prop != NULL) {
312 prop->mType = kTypeInt32;
313 prop->u.int32Value = value;
314 }
Ray Essick3938dc62016-11-01 08:56:56 -0700315}
316
Ray Essickb5fac8e2016-12-12 11:33:56 -0800317void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
318 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700319 if (prop != NULL) {
320 prop->mType = kTypeInt64;
321 prop->u.int64Value = value;
322 }
Ray Essick3938dc62016-11-01 08:56:56 -0700323}
324
Ray Essickb5fac8e2016-12-12 11:33:56 -0800325void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
326 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700327 if (prop != NULL) {
328 prop->mType = kTypeDouble;
329 prop->u.doubleValue = value;
330 }
Ray Essick3938dc62016-11-01 08:56:56 -0700331}
332
Ray Essickb5fac8e2016-12-12 11:33:56 -0800333void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
334
335 Prop *prop = allocateProp(name);
336 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700337 if (prop != NULL) {
338 prop->mType = kTypeCString;
339 prop->u.CStringValue = strdup(value);
340 }
Ray Essick3938dc62016-11-01 08:56:56 -0700341}
342
Ray Essickb5fac8e2016-12-12 11:33:56 -0800343void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
344 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700345 if (prop != NULL) {
346 prop->mType = kTypeRate;
347 prop->u.rate.count = count;
348 prop->u.rate.duration = duration;
349 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800350}
351
352
Ray Essick3938dc62016-11-01 08:56:56 -0700353// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800354void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
355 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700356 if (prop == NULL) {
357 return;
358 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800359 switch (prop->mType) {
360 case kTypeInt32:
361 prop->u.int32Value += value;
362 break;
363 default:
364 clearPropValue(prop);
365 prop->mType = kTypeInt32;
366 prop->u.int32Value = value;
367 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700368 }
Ray Essick3938dc62016-11-01 08:56:56 -0700369}
370
Ray Essickb5fac8e2016-12-12 11:33:56 -0800371void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
372 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700373 if (prop == NULL) {
374 return;
375 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800376 switch (prop->mType) {
377 case kTypeInt64:
378 prop->u.int64Value += value;
379 break;
380 default:
381 clearPropValue(prop);
382 prop->mType = kTypeInt64;
383 prop->u.int64Value = value;
384 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700385 }
Ray Essick3938dc62016-11-01 08:56:56 -0700386}
387
Ray Essickb5fac8e2016-12-12 11:33:56 -0800388void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
389 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700390 if (prop == NULL) {
391 return;
392 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800393 switch (prop->mType) {
394 case kTypeRate:
395 prop->u.rate.count += count;
396 prop->u.rate.duration += duration;
397 break;
398 default:
399 clearPropValue(prop);
400 prop->mType = kTypeRate;
401 prop->u.rate.count = count;
402 prop->u.rate.duration = duration;
403 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700404 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800405}
406
407void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
408 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700409 if (prop == NULL) {
410 return;
411 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800412 switch (prop->mType) {
413 case kTypeDouble:
414 prop->u.doubleValue += value;
415 break;
416 default:
417 clearPropValue(prop);
418 prop->mType = kTypeDouble;
419 prop->u.doubleValue = value;
420 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700421 }
Ray Essick3938dc62016-11-01 08:56:56 -0700422}
423
424// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800425bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
426 Prop *prop = findProp(name);
427 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700428 return false;
429 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800430 if (value != NULL) {
431 *value = prop->u.int32Value;
432 }
Ray Essick3938dc62016-11-01 08:56:56 -0700433 return true;
434}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800435
436bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
437 Prop *prop = findProp(name);
438 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700439 return false;
440 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800441 if (value != NULL) {
442 *value = prop->u.int64Value;
443 }
Ray Essick3938dc62016-11-01 08:56:56 -0700444 return true;
445}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800446
447bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
448 Prop *prop = findProp(name);
449 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700450 return false;
451 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800452 if (count != NULL) {
453 *count = prop->u.rate.count;
454 }
455 if (duration != NULL) {
456 *duration = prop->u.rate.duration;
457 }
458 if (rate != NULL) {
459 double r = 0.0;
460 if (prop->u.rate.duration != 0) {
461 r = prop->u.rate.count / (double) prop->u.rate.duration;
462 }
463 *rate = r;
464 }
465 return true;
466}
467
468bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
469 Prop *prop = findProp(name);
470 if (prop == NULL || prop->mType != kTypeDouble) {
471 return false;
472 }
473 if (value != NULL) {
474 *value = prop->u.doubleValue;
475 }
Ray Essick3938dc62016-11-01 08:56:56 -0700476 return true;
477}
478
479// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800480bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
481 Prop *prop = findProp(name);
482 if (prop == NULL || prop->mType != kTypeDouble) {
Ray Essick3938dc62016-11-01 08:56:56 -0700483 return false;
484 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800485 if (value != NULL) {
486 *value = strdup(prop->u.CStringValue);
487 }
Ray Essick3938dc62016-11-01 08:56:56 -0700488 return true;
489}
490
491// remove indicated keys and their values
492// return value is # keys removed
493int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
494 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800495 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700496 return -1;
497 }
498 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800499 const char *name = attrs[i];
500 size_t len = strlen(name);
501 size_t j = findPropIndex(name, len);
502 if (j >= mPropCount) {
503 // not there
504 continue;
505 } else if (j+1 == mPropCount) {
506 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700507 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800508 clearProp(&mProps[j]);
509 mPropCount--;
510 } else {
511 // in the middle, bring last one down and shorten
512 zapped++;
513 clearProp(&mProps[j]);
514 mProps[j] = mProps[mPropCount-1];
515 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700516 }
517 }
518 return zapped;
519}
520
521// remove any keys NOT in the provided list
522// return value is # keys removed
523int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
524 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800525 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700526 return -1;
527 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800528 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
529 Prop *prop = &mProps[i];
530 for (ssize_t j = 0; j < n ; j++) {
531 if (strcmp(prop->mName, attrs[j]) == 0) {
532 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700533 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800534 if (i != (ssize_t)(mPropCount-1)) {
535 *prop = mProps[mPropCount-1];
536 }
537 initProp(&mProps[mPropCount-1]);
538 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700539 break;
540 }
541 }
542 }
543 return zapped;
544}
545
546// remove a single key
547// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800548int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
549 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700550}
551
Ray Essick3938dc62016-11-01 08:56:56 -0700552// handle individual items/properties stored within the class
553//
Ray Essick3938dc62016-11-01 08:56:56 -0700554
Ray Essickb5fac8e2016-12-12 11:33:56 -0800555void MediaAnalyticsItem::initProp(Prop *prop) {
556 if (prop != NULL) {
557 prop->mName = NULL;
558 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700559
Ray Essickb5fac8e2016-12-12 11:33:56 -0800560 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700561 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800562}
563
564void MediaAnalyticsItem::clearProp(Prop *prop)
565{
566 if (prop != NULL) {
567 if (prop->mName != NULL) {
568 free((void *)prop->mName);
569 prop->mName = NULL;
570 prop->mNameLen = 0;
571 }
572
573 clearPropValue(prop);
574 }
575}
576
577void MediaAnalyticsItem::clearPropValue(Prop *prop)
578{
579 if (prop != NULL) {
580 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
581 free(prop->u.CStringValue);
582 prop->u.CStringValue = NULL;
583 }
584 prop->mType = kTypeNone;
585 }
586}
587
588void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
589{
590 // get rid of any pointers in the dst
591 clearProp(dst);
592
593 *dst = *src;
594
595 // fix any pointers that we blindly copied, so we have our own copies
596 if (dst->mName) {
597 void *p = malloc(dst->mNameLen + 1);
598 memcpy (p, src->mName, dst->mNameLen + 1);
599 dst->mName = (const char *) p;
600 }
601 if (dst->mType == kTypeCString) {
602 dst->u.CStringValue = strdup(src->u.CStringValue);
603 }
604}
605
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700606bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800607{
608 if (increment <= 0) {
609 increment = kGrowProps;
610 }
611 int nsize = mPropSize + increment;
612 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
613
614 if (ni != NULL) {
615 for (int i = mPropSize; i < nsize; i++) {
616 initProp(&ni[i]);
617 }
618 mProps = ni;
619 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700620 return true;
621 } else {
622 ALOGW("MediaAnalyticsItem::growProps fails");
623 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800624 }
Ray Essick3938dc62016-11-01 08:56:56 -0700625}
626
627// Parcel / serialize things for binder calls
628//
629
630int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
631 // into 'this' object
632 // .. we make a copy of the string to put away.
633 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700634 mPid = data.readInt32();
635 mUid = data.readInt32();
636 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800637 mPkgVersionCode = data.readInt64();
Ray Essick3938dc62016-11-01 08:56:56 -0700638 mSessionID = data.readInt64();
639 mFinalized = data.readInt32();
640 mTimestamp = data.readInt64();
641
642 int count = data.readInt32();
643 for (int i = 0; i < count ; i++) {
644 MediaAnalyticsItem::Attr attr = data.readCString();
645 int32_t ztype = data.readInt32();
646 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800647 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700648 setInt32(attr, data.readInt32());
649 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800650 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700651 setInt64(attr, data.readInt64());
652 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800653 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700654 setDouble(attr, data.readDouble());
655 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800656 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700657 setCString(attr, data.readCString());
658 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800659 case MediaAnalyticsItem::kTypeRate:
660 {
661 int64_t count = data.readInt64();
662 int64_t duration = data.readInt64();
663 setRate(attr, count, duration);
664 }
665 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700666 default:
667 ALOGE("reading bad item type: %d, idx %d",
668 ztype, i);
669 return -1;
670 }
671 }
672
673 return 0;
674}
675
676int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
677 if (data == NULL) return -1;
678
679
680 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700681 data->writeInt32(mPid);
682 data->writeInt32(mUid);
683 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800684 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700685 data->writeInt64(mSessionID);
686 data->writeInt32(mFinalized);
687 data->writeInt64(mTimestamp);
688
689 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800690 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700691 data->writeInt32(count);
692 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800693 Prop *prop = &mProps[i];
694 data->writeCString(prop->mName);
695 data->writeInt32(prop->mType);
696 switch (prop->mType) {
697 case MediaAnalyticsItem::kTypeInt32:
698 data->writeInt32(prop->u.int32Value);
699 break;
700 case MediaAnalyticsItem::kTypeInt64:
701 data->writeInt64(prop->u.int64Value);
702 break;
703 case MediaAnalyticsItem::kTypeDouble:
704 data->writeDouble(prop->u.doubleValue);
705 break;
706 case MediaAnalyticsItem::kTypeRate:
707 data->writeInt64(prop->u.rate.count);
708 data->writeInt64(prop->u.rate.duration);
709 break;
710 case MediaAnalyticsItem::kTypeCString:
711 data->writeCString(prop->u.CStringValue);
712 break;
713 default:
714 ALOGE("found bad Prop type: %d, idx %d, name %s",
715 prop->mType, i, prop->mName);
716 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700717 }
718 }
719
720 return 0;
721}
722
723
Ray Essick783bd0d2018-01-11 11:10:35 -0800724std::string MediaAnalyticsItem::toString() {
Ray Essickf65f4212017-08-31 11:41:19 -0700725 return toString(-1);
726}
Ray Essick3938dc62016-11-01 08:56:56 -0700727
Ray Essick783bd0d2018-01-11 11:10:35 -0800728std::string MediaAnalyticsItem::toString(int version) {
Ray Essickf65f4212017-08-31 11:41:19 -0700729
730 // v0 : released with 'o'
731 // v1 : bug fix (missing pid/finalized separator),
732 // adds apk name, apk version code
733
734 if (version <= PROTO_FIRST) {
735 // default to original v0 format, until proper parsers are in place
736 version = PROTO_V0;
737 } else if (version > PROTO_LAST) {
738 version = PROTO_LAST;
739 }
740
Ray Essick783bd0d2018-01-11 11:10:35 -0800741 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800742 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700743
Ray Essickf65f4212017-08-31 11:41:19 -0700744 if (version == PROTO_V0) {
745 result = "(";
746 } else {
747 snprintf(buffer, sizeof(buffer), "[%d:", version);
748 result.append(buffer);
749 }
750
Ray Essick3938dc62016-11-01 08:56:56 -0700751 // same order as we spill into the parcel, although not required
752 // key+session are our primary matching criteria
753 result.append(mKey.c_str());
754 result.append(":");
755 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
756 result.append(buffer);
757
Ray Essickf65f4212017-08-31 11:41:19 -0700758 snprintf(buffer, sizeof(buffer), "%d:", mUid);
759 result.append(buffer);
760
761 if (version >= PROTO_V1) {
762 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800763 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700764 result.append(buffer);
765 }
766
767 // in 'o' (v1) , the separator between pid and finalized was omitted
768 if (version <= PROTO_V0) {
769 snprintf(buffer, sizeof(buffer), "%d", mPid);
770 } else {
771 snprintf(buffer, sizeof(buffer), "%d:", mPid);
772 }
Ray Essick3938dc62016-11-01 08:56:56 -0700773 result.append(buffer);
774
775 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
776 result.append(buffer);
777 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
778 result.append(buffer);
779
780 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800781 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700782 snprintf(buffer, sizeof(buffer), "%d:", count);
783 result.append(buffer);
784 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800785 Prop *prop = &mProps[i];
786 switch (prop->mType) {
787 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700788 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800789 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700790 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800791 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700792 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800793 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700794 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800795 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700796 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800797 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700798 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800799 case MediaAnalyticsItem::kTypeRate:
800 snprintf(buffer,sizeof(buffer),
801 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
802 prop->u.rate.count, prop->u.rate.duration);
803 break;
804 case MediaAnalyticsItem::kTypeCString:
805 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700806 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800807 // XXX: sanitize string for ':' '='
808 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700809 buffer[0] = ':';
810 buffer[1] = '\0';
811 break;
812 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800813 ALOGE("to_String bad item type: %d for %s",
814 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700815 break;
816 }
817 result.append(buffer);
818 }
819
Ray Essickf65f4212017-08-31 11:41:19 -0700820 if (version == PROTO_V0) {
821 result.append(")");
822 } else {
823 result.append("]");
824 }
Ray Essick3938dc62016-11-01 08:56:56 -0700825
826 return result;
827}
828
829// for the lazy, we offer methods that finds the service and
830// calls the appropriate daemon
831bool MediaAnalyticsItem::selfrecord() {
832 return selfrecord(false);
833}
834
835bool MediaAnalyticsItem::selfrecord(bool forcenew) {
836
Ray Essickb5fac8e2016-12-12 11:33:56 -0800837 if (DEBUG_API) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800838 std::string p = this->toString();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800839 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
840 }
Ray Essick3938dc62016-11-01 08:56:56 -0700841
842 sp<IMediaAnalyticsService> svc = getInstance();
843
844 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700845 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
846 if (newid == SessionIDInvalid) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800847 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700848 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
849 return false;
850 }
Ray Essick3938dc62016-11-01 08:56:56 -0700851 return true;
852 } else {
Ray Essick783bd0d2018-01-11 11:10:35 -0800853 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700854 ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700855 return false;
856 }
857}
858
859// get a connection we can reuse for most of our lifetime
860// static
861sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
862static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700863static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700864
865//static
866bool MediaAnalyticsItem::isEnabled() {
867 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
868
869 if (enabled == -1) {
870 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
871 }
872 if (enabled == -1) {
873 enabled = MediaAnalyticsItem::EnabledProperty_default;
874 }
875 if (enabled <= 0) {
876 return false;
877 }
878 return true;
879}
880
Ray Essick2ab3c432017-10-02 09:29:49 -0700881
882// monitor health of our connection to the metrics service
883class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
884 virtual void binderDied(const wp<IBinder> &) {
885 ALOGW("Reacquire service connection on next request");
886 MediaAnalyticsItem::dropInstance();
887 }
888};
889
890static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
891
892// static
893void MediaAnalyticsItem::dropInstance() {
894 Mutex::Autolock _l(sInitMutex);
895 remainingBindAttempts = SVC_TRIES;
896 sAnalyticsService = NULL;
897}
898
Ray Essick3938dc62016-11-01 08:56:56 -0700899//static
900sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700901
Ray Essickd38e1742017-01-23 15:17:06 -0800902 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700903 int enabled = isEnabled();
904
905 if (enabled == false) {
906 if (DEBUG_SERVICEACCESS) {
907 ALOGD("disabled");
908 }
909 return NULL;
910 }
911
Ray Essick79a89ef2017-04-24 15:52:54 -0700912 // completely skip logging from certain UIDs. We do this here
913 // to avoid the multi-second timeouts while we learn that
914 // sepolicy will not let us find the service.
915 // We do this only for a select set of UIDs
916 // The sepolicy protection is still in place, we just want a faster
917 // response from this specific, small set of uids.
918 {
919 uid_t uid = getuid();
920 switch (uid) {
921 case AID_RADIO: // telephony subsystem, RIL
922 return NULL;
923 break;
924 default:
925 // let sepolicy deny access if appropriate
926 break;
927 }
928 }
929
Ray Essick3938dc62016-11-01 08:56:56 -0700930 {
931 Mutex::Autolock _l(sInitMutex);
932 const char *badness = "";
933
Ray Essick2ab3c432017-10-02 09:29:49 -0700934 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -0800935 // (1) we haven't tried to initialize it yet
936 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -0700937 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700938 sp<IServiceManager> sm = defaultServiceManager();
939 if (sm != NULL) {
940 sp<IBinder> binder = sm->getService(String16(servicename));
941 if (binder != NULL) {
942 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -0700943 if (sNotifier != NULL) {
944 sNotifier = NULL;
945 }
946 sNotifier = new MediaMetricsDeathNotifier();
947 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700948 } else {
949 badness = "did not find service";
950 }
951 } else {
952 badness = "No Service Manager access";
953 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800954
955 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700956 if (remainingBindAttempts > 0) {
957 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800958 }
959 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700960 ALOGD("Unable to bind to service %s: %s", servicename, badness);
961 }
962 }
963 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800964
Ray Essick3938dc62016-11-01 08:56:56 -0700965 return sAnalyticsService;
966 }
967}
968
Ray Essick3938dc62016-11-01 08:56:56 -0700969// merge the info from 'incoming' into this record.
970// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800971bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700972
973 // if I don't have key or session id, take them from incoming
974 // 'this' should never be missing both of them...
975 if (mKey.empty()) {
976 mKey = incoming->mKey;
977 } else if (mSessionID == 0) {
978 mSessionID = incoming->mSessionID;
979 }
980
981 // we always take the more recent 'finalized' value
982 setFinalized(incoming->getFinalized());
983
984 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800985 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700986 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800987 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800988 const char *p = iprop->mName;
989 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700990
991 // should ignore a zero length name...
992 if (len == 0) {
993 continue;
994 }
995
996 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700997
Ray Essickb5fac8e2016-12-12 11:33:56 -0800998 if (oprop == NULL) {
999 // no oprop, so we insert the new one
1000 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001001 if (oprop != NULL) {
1002 copyProp(oprop, iprop);
1003 } else {
1004 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -08001005 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001006 } else {
1007 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -07001008 }
1009 }
1010
1011 // not sure when we'd return false...
1012 return true;
1013}
1014
1015} // namespace android
1016