blob: a4efa495fd2c37c490e67e08e6c9721d1146a60e [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
Andy Hunga87e69c2019-10-18 10:07:40 -070025#include <mutex>
26
Ray Essick3938dc62016-11-01 08:56:56 -070027#include <binder/Parcel.h>
28#include <utils/Errors.h>
29#include <utils/Log.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <utils/SortedVector.h>
31#include <utils/threads.h>
32
Ray Essick3938dc62016-11-01 08:56:56 -070033#include <binder/IServiceManager.h>
34#include <media/IMediaAnalyticsService.h>
35#include <media/MediaAnalyticsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070036#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070037
38namespace android {
39
40#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080041#define DEBUG_API 0
42#define DEBUG_ALLOCATIONS 0
43
44// after this many failed attempts, we stop trying [from this process] and just say that
45// the service is off.
46#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070047
Ray Essickba8c4842019-01-18 11:35:33 -080048// So caller doesn't need to know size of allocated space
49MediaAnalyticsItem *MediaAnalyticsItem::create()
50{
51 return MediaAnalyticsItem::create(kKeyNone);
52}
53
54MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
55{
56 MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
57 return item;
58}
Ray Essick3938dc62016-11-01 08:56:56 -070059
Ray Essickbf536ac2019-08-26 11:04:28 -070060MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
61 MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
62 return item;
63}
64
65mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
66 mediametrics_handle_t handle = (mediametrics_handle_t) item;
67 return handle;
68}
69
Ray Essick3938dc62016-11-01 08:56:56 -070070MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080071 if (DEBUG_ALLOCATIONS) {
72 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
73 }
Ray Essick3938dc62016-11-01 08:56:56 -070074 clear();
75}
76
Ray Essickb5fac8e2016-12-12 11:33:56 -080077void MediaAnalyticsItem::clear() {
78
79 // clean allocated storage from key
80 mKey.clear();
81
82 // clean attributes
83 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -070084 for (size_t i = 0 ; i < mPropCount; i++ ) {
Andy Hungaeef7882019-10-18 15:18:14 -070085 mProps[i].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -080086 }
87 // the attribute records themselves
88 if (mProps != NULL) {
89 free(mProps);
90 mProps = NULL;
91 }
92 mPropSize = 0;
93 mPropCount = 0;
94
95 return;
96}
97
98// make a deep copy of myself
99MediaAnalyticsItem *MediaAnalyticsItem::dup() {
100 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
101
102 if (dst != NULL) {
103 // key as part of constructor
104 dst->mPid = this->mPid;
105 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700106 dst->mPkgName = this->mPkgName;
107 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800108 dst->mTimestamp = this->mTimestamp;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800109
110 // properties aka attributes
111 dst->growProps(this->mPropCount);
112 for(size_t i=0;i<mPropCount;i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700113 dst->mProps[i] = this->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800114 }
115 dst->mPropCount = this->mPropCount;
116 }
117
118 return dst;
119}
120
Ray Essick3938dc62016-11-01 08:56:56 -0700121MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
122 mTimestamp = ts;
123 return *this;
124}
125
126nsecs_t MediaAnalyticsItem::getTimestamp() const {
127 return mTimestamp;
128}
129
130MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
131 mPid = pid;
132 return *this;
133}
134
135pid_t MediaAnalyticsItem::getPid() const {
136 return mPid;
137}
138
139MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
140 mUid = uid;
141 return *this;
142}
143
144uid_t MediaAnalyticsItem::getUid() const {
145 return mUid;
146}
147
Ray Essick783bd0d2018-01-11 11:10:35 -0800148MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700149 mPkgName = pkgName;
150 return *this;
151}
152
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800153MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700154 mPkgVersionCode = pkgVersionCode;
155 return *this;
156}
157
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800158int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700159 return mPkgVersionCode;
160}
161
Ray Essickb5fac8e2016-12-12 11:33:56 -0800162// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700163MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700164 mKey = key;
165 return *this;
166}
167
Ray Essickb5fac8e2016-12-12 11:33:56 -0800168// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700169int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800170 return mPropCount;
171}
172
173// find the proper entry in the list
Andy Hungaeef7882019-10-18 15:18:14 -0700174size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len) const
Ray Essickb5fac8e2016-12-12 11:33:56 -0800175{
176 size_t i = 0;
177 for (; i < mPropCount; i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700178 if (mProps[i].isNamed(name, len)) break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800179 }
180 return i;
181}
182
Andy Hungaeef7882019-10-18 15:18:14 -0700183MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800184 size_t len = strlen(name);
185 size_t i = findPropIndex(name, len);
186 if (i < mPropCount) {
187 return &mProps[i];
188 }
189 return NULL;
190}
191
Ray Essick9ce18f72018-05-07 15:54:30 -0700192// consider this "find-or-allocate".
193// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800194MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
195 size_t len = strlen(name);
196 size_t i = findPropIndex(name, len);
197 Prop *prop;
198
199 if (i < mPropCount) {
200 prop = &mProps[i];
201 } else {
202 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700203 if (growProps() == false) {
204 ALOGE("failed allocation for new props");
205 return NULL;
206 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800207 }
208 i = mPropCount++;
209 prop = &mProps[i];
210 prop->setName(name, len);
211 }
212
213 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700214}
215
Ray Essickf65f4212017-08-31 11:41:19 -0700216// used within the summarizers; return whether property existed
217bool MediaAnalyticsItem::removeProp(const char *name) {
218 size_t len = strlen(name);
219 size_t i = findPropIndex(name, len);
220 if (i < mPropCount) {
Andy Hungaeef7882019-10-18 15:18:14 -0700221 mProps[i].clear();
Ray Essickf65f4212017-08-31 11:41:19 -0700222 if (i != mPropCount-1) {
223 // in the middle, bring last one down to fill gap
Andy Hungaeef7882019-10-18 15:18:14 -0700224 mProps[i].swap(mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700225 }
226 mPropCount--;
227 return true;
228 }
229 return false;
230}
231
Ray Essick3938dc62016-11-01 08:56:56 -0700232// remove indicated keys and their values
233// return value is # keys removed
234int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
235 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800236 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700237 return -1;
238 }
239 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800240 const char *name = attrs[i];
241 size_t len = strlen(name);
242 size_t j = findPropIndex(name, len);
243 if (j >= mPropCount) {
244 // not there
245 continue;
246 } else if (j+1 == mPropCount) {
247 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700248 zapped++;
Andy Hungaeef7882019-10-18 15:18:14 -0700249 mProps[j].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800250 mPropCount--;
251 } else {
252 // in the middle, bring last one down and shorten
253 zapped++;
Andy Hungaeef7882019-10-18 15:18:14 -0700254 mProps[j].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800255 mProps[j] = mProps[mPropCount-1];
256 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700257 }
258 }
259 return zapped;
260}
261
262// remove any keys NOT in the provided list
263// return value is # keys removed
264int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
265 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800266 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700267 return -1;
268 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800269 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
270 Prop *prop = &mProps[i];
271 for (ssize_t j = 0; j < n ; j++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700272 if (prop->isNamed(attrs[j])) {
273 prop->clear();
Ray Essick3938dc62016-11-01 08:56:56 -0700274 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800275 if (i != (ssize_t)(mPropCount-1)) {
276 *prop = mProps[mPropCount-1];
277 }
Andy Hungaeef7882019-10-18 15:18:14 -0700278 mProps[mPropCount-1].clear();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800279 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700280 break;
281 }
282 }
283 }
284 return zapped;
285}
286
287// remove a single key
288// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800289int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
290 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700291}
292
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700293bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800294{
295 if (increment <= 0) {
296 increment = kGrowProps;
297 }
298 int nsize = mPropSize + increment;
299 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
300
301 if (ni != NULL) {
302 for (int i = mPropSize; i < nsize; i++) {
Andy Hungaeef7882019-10-18 15:18:14 -0700303 new (&ni[i]) Prop(); // placement new
Ray Essickb5fac8e2016-12-12 11:33:56 -0800304 }
305 mProps = ni;
306 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700307 return true;
308 } else {
309 ALOGW("MediaAnalyticsItem::growProps fails");
310 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800311 }
Ray Essick3938dc62016-11-01 08:56:56 -0700312}
313
314// Parcel / serialize things for binder calls
315//
316
317int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800318 int32_t version = data.readInt32();
319
320 switch(version) {
321 case 0:
322 return readFromParcel0(data);
323 break;
324 default:
325 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
326 return -1;
327 }
328}
329
330int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700331 // into 'this' object
332 // .. we make a copy of the string to put away.
333 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700334 mPid = data.readInt32();
335 mUid = data.readInt32();
336 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800337 mPkgVersionCode = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800338 // We no longer pay attention to user setting of finalized, BUT it's
339 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700340 mTimestamp = data.readInt64();
341
342 int count = data.readInt32();
343 for (int i = 0; i < count ; i++) {
344 MediaAnalyticsItem::Attr attr = data.readCString();
345 int32_t ztype = data.readInt32();
346 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800347 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700348 setInt32(attr, data.readInt32());
349 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800350 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700351 setInt64(attr, data.readInt64());
352 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800353 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700354 setDouble(attr, data.readDouble());
355 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800356 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700357 setCString(attr, data.readCString());
358 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800359 case MediaAnalyticsItem::kTypeRate:
360 {
361 int64_t count = data.readInt64();
362 int64_t duration = data.readInt64();
363 setRate(attr, count, duration);
364 }
365 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700366 default:
367 ALOGE("reading bad item type: %d, idx %d",
368 ztype, i);
369 return -1;
370 }
371 }
372
373 return 0;
374}
375
376int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800377
Ray Essick3938dc62016-11-01 08:56:56 -0700378 if (data == NULL) return -1;
379
Ray Essickba8c4842019-01-18 11:35:33 -0800380 int32_t version = 0;
381 data->writeInt32(version);
382
383 switch(version) {
384 case 0:
385 return writeToParcel0(data);
386 break;
387 default:
388 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
389 return -1;
390 }
391}
392
393int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700394
395 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700396 data->writeInt32(mPid);
397 data->writeInt32(mUid);
398 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800399 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700400 data->writeInt64(mTimestamp);
401
402 // set of items
Andy Hungaeef7882019-10-18 15:18:14 -0700403 const size_t count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700404 data->writeInt32(count);
Andy Hungaeef7882019-10-18 15:18:14 -0700405 for (size_t i = 0 ; i < count; i++ ) {
406 mProps[i].writeToParcel(data);
Ray Essick3938dc62016-11-01 08:56:56 -0700407 }
Ray Essick3938dc62016-11-01 08:56:56 -0700408 return 0;
409}
410
Ray Essick20147322018-11-17 09:08:39 -0800411const char *MediaAnalyticsItem::toCString() {
412 return toCString(PROTO_LAST);
413}
414
415const char * MediaAnalyticsItem::toCString(int version) {
416 std::string val = toString(version);
417 return strdup(val.c_str());
418}
419
Andy Hung17dbaf22019-10-11 14:06:31 -0700420std::string MediaAnalyticsItem::toString() const {
Ray Essick5b77bd22018-01-23 16:11:06 -0800421 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700422}
Ray Essick3938dc62016-11-01 08:56:56 -0700423
Andy Hung17dbaf22019-10-11 14:06:31 -0700424std::string MediaAnalyticsItem::toString(int version) const {
Ray Essickf65f4212017-08-31 11:41:19 -0700425
426 // v0 : released with 'o'
427 // v1 : bug fix (missing pid/finalized separator),
428 // adds apk name, apk version code
429
430 if (version <= PROTO_FIRST) {
431 // default to original v0 format, until proper parsers are in place
432 version = PROTO_V0;
433 } else if (version > PROTO_LAST) {
434 version = PROTO_LAST;
435 }
436
Ray Essick783bd0d2018-01-11 11:10:35 -0800437 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800438 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700439
Ray Essickf65f4212017-08-31 11:41:19 -0700440 if (version == PROTO_V0) {
441 result = "(";
442 } else {
443 snprintf(buffer, sizeof(buffer), "[%d:", version);
444 result.append(buffer);
445 }
446
Ray Essick3938dc62016-11-01 08:56:56 -0700447 // same order as we spill into the parcel, although not required
448 // key+session are our primary matching criteria
449 result.append(mKey.c_str());
Andy Hunga87e69c2019-10-18 10:07:40 -0700450 result.append(":0:"); // sessionID
Ray Essick3938dc62016-11-01 08:56:56 -0700451
Ray Essickf65f4212017-08-31 11:41:19 -0700452 snprintf(buffer, sizeof(buffer), "%d:", mUid);
453 result.append(buffer);
454
455 if (version >= PROTO_V1) {
456 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800457 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700458 result.append(buffer);
459 }
460
461 // in 'o' (v1) , the separator between pid and finalized was omitted
462 if (version <= PROTO_V0) {
463 snprintf(buffer, sizeof(buffer), "%d", mPid);
464 } else {
465 snprintf(buffer, sizeof(buffer), "%d:", mPid);
466 }
Ray Essick3938dc62016-11-01 08:56:56 -0700467 result.append(buffer);
468
Andy Hunga87e69c2019-10-18 10:07:40 -0700469 snprintf(buffer, sizeof(buffer), "%d:", 0 /* finalized */); // TODO: remove this.
Ray Essick3938dc62016-11-01 08:56:56 -0700470 result.append(buffer);
471 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
472 result.append(buffer);
473
474 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800475 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700476 snprintf(buffer, sizeof(buffer), "%d:", count);
477 result.append(buffer);
478 for (int i = 0 ; i < count; i++ ) {
Andy Hungaeef7882019-10-18 15:18:14 -0700479 mProps[i].toString(buffer, sizeof(buffer));
480 result.append(buffer);
Ray Essick3938dc62016-11-01 08:56:56 -0700481 }
482
Ray Essickf65f4212017-08-31 11:41:19 -0700483 if (version == PROTO_V0) {
484 result.append(")");
485 } else {
486 result.append("]");
487 }
Ray Essick3938dc62016-11-01 08:56:56 -0700488
489 return result;
490}
491
492// for the lazy, we offer methods that finds the service and
493// calls the appropriate daemon
494bool MediaAnalyticsItem::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700495 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700496 sp<IMediaAnalyticsService> svc = getInstance();
Ray Essick3938dc62016-11-01 08:56:56 -0700497 if (svc != NULL) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700498 status_t status = svc->submit(this);
499 if (status != NO_ERROR) {
500 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick2ab3c432017-10-02 09:29:49 -0700501 return false;
502 }
Ray Essick3938dc62016-11-01 08:56:56 -0700503 return true;
504 } else {
505 return false;
506 }
507}
508
Ray Essick3938dc62016-11-01 08:56:56 -0700509
510//static
511bool MediaAnalyticsItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700512 // completely skip logging from certain UIDs. We do this here
513 // to avoid the multi-second timeouts while we learn that
514 // sepolicy will not let us find the service.
515 // We do this only for a select set of UIDs
516 // The sepolicy protection is still in place, we just want a faster
517 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700518
Andy Hunga87e69c2019-10-18 10:07:40 -0700519 // This is checked only once in the lifetime of the process.
520 const uid_t uid = getuid();
521 switch (uid) {
522 case AID_RADIO: // telephony subsystem, RIL
523 return false;
524 }
525
526 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700527 if (enabled == -1) {
528 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
529 }
530 if (enabled == -1) {
531 enabled = MediaAnalyticsItem::EnabledProperty_default;
532 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700533 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700534}
535
Ray Essick2ab3c432017-10-02 09:29:49 -0700536// monitor health of our connection to the metrics service
537class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
538 virtual void binderDied(const wp<IBinder> &) {
539 ALOGW("Reacquire service connection on next request");
540 MediaAnalyticsItem::dropInstance();
541 }
542};
543
Andy Hunga87e69c2019-10-18 10:07:40 -0700544static sp<MediaMetricsDeathNotifier> sNotifier;
545// static
546sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
547static std::mutex sServiceMutex;
548static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700549
550// static
551void MediaAnalyticsItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700552 std::lock_guard _l(sServiceMutex);
553 sRemainingBindAttempts = SVC_TRIES;
554 sAnalyticsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700555}
556
Ray Essick3938dc62016-11-01 08:56:56 -0700557//static
558sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essickd38e1742017-01-23 15:17:06 -0800559 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700560 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700561
562 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700563 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
564 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700565 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700566 std::lock_guard _l(sServiceMutex);
567 // think of remainingBindAttempts as telling us whether service == nullptr because
568 // (1) we haven't tried to initialize it yet
569 // (2) we've tried to initialize it, but failed.
570 if (sAnalyticsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700571 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700572 sp<IServiceManager> sm = defaultServiceManager();
573 if (sm != nullptr) {
574 sp<IBinder> binder = sm->getService(String16(servicename));
575 if (binder != nullptr) {
576 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
577 sNotifier = new MediaMetricsDeathNotifier();
578 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700579 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700580 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700581 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700582 } else {
583 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700584 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700585 if (sAnalyticsService == nullptr) {
586 if (sRemainingBindAttempts > 0) {
587 sRemainingBindAttempts--;
588 }
589 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
590 __func__, servicename, badness);
591 }
Ray Essick3938dc62016-11-01 08:56:56 -0700592 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700593 return sAnalyticsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700594}
595
Ray Essick3938dc62016-11-01 08:56:56 -0700596// merge the info from 'incoming' into this record.
597// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800598bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700599
600 // if I don't have key or session id, take them from incoming
601 // 'this' should never be missing both of them...
602 if (mKey.empty()) {
603 mKey = incoming->mKey;
Ray Essick3938dc62016-11-01 08:56:56 -0700604 }
605
Ray Essick3938dc62016-11-01 08:56:56 -0700606 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -0800607 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700608 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800609 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800610 const char *p = iprop->mName;
611 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700612
613 // should ignore a zero length name...
614 if (len == 0) {
615 continue;
616 }
617
618 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700619
Ray Essickb5fac8e2016-12-12 11:33:56 -0800620 if (oprop == NULL) {
621 // no oprop, so we insert the new one
622 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700623 if (oprop != NULL) {
Andy Hungaeef7882019-10-18 15:18:14 -0700624 *oprop = *iprop;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700625 } else {
626 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800627 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700628 } else {
Andy Hungaeef7882019-10-18 15:18:14 -0700629 *oprop = *iprop;
Ray Essick3938dc62016-11-01 08:56:56 -0700630 }
631 }
632
633 // not sure when we'd return false...
634 return true;
635}
636
Ray Essickba8c4842019-01-18 11:35:33 -0800637// a byte array; contents are
638// overall length (uint32) including the length field itself
639// encoding version (uint32)
640// count of properties (uint32)
641// N copies of:
642// property name as length(int16), bytes
643// the bytes WILL include the null terminator of the name
644// type (uint8 -- 1 byte)
645// size of value field (int16 -- 2 bytes)
646// value (size based on type)
647// int32, int64, double -- little endian 4/8/8 bytes respectively
648// cstring -- N bytes of value [WITH terminator]
649
650enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
651
652bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
653
654 char *build = NULL;
655
656 if (pbuffer == NULL || plength == NULL)
657 return false;
658
659 // consistency for the caller, who owns whatever comes back in this pointer.
660 *pbuffer = NULL;
661
662 // first, let's calculate sizes
663 int32_t goal = 0;
664 int32_t version = 0;
665
666 goal += sizeof(uint32_t); // overall length, including the length field
667 goal += sizeof(uint32_t); // encoding version
668 goal += sizeof(uint32_t); // # properties
669
670 int32_t count = mPropCount;
671 for (int i = 0 ; i < count; i++ ) {
672 Prop *prop = &mProps[i];
673 goal += sizeof(uint16_t); // name length
674 goal += strlen(prop->mName) + 1; // string + null
675 goal += sizeof(uint8_t); // type
676 goal += sizeof(uint16_t); // size of value
677 switch (prop->mType) {
678 case MediaAnalyticsItem::kTypeInt32:
679 goal += sizeof(uint32_t);
680 break;
681 case MediaAnalyticsItem::kTypeInt64:
682 goal += sizeof(uint64_t);
683 break;
684 case MediaAnalyticsItem::kTypeDouble:
685 goal += sizeof(double);
686 break;
687 case MediaAnalyticsItem::kTypeRate:
688 goal += 2 * sizeof(uint64_t);
689 break;
690 case MediaAnalyticsItem::kTypeCString:
691 // length + actual string + null
692 goal += strlen(prop->u.CStringValue) + 1;
693 break;
694 default:
695 ALOGE("found bad Prop type: %d, idx %d, name %s",
696 prop->mType, i, prop->mName);
697 return false;
698 }
699 }
700
701 // now that we have a size... let's allocate and fill
702 build = (char *)malloc(goal);
703 if (build == NULL)
704 return false;
705
706 memset(build, 0, goal);
707
708 char *filling = build;
709
710#define _INSERT(val, size) \
711 { memcpy(filling, &(val), (size)); filling += (size);}
712#define _INSERTSTRING(val, size) \
713 { memcpy(filling, (val), (size)); filling += (size);}
714
715 _INSERT(goal, sizeof(int32_t));
716 _INSERT(version, sizeof(int32_t));
717 _INSERT(count, sizeof(int32_t));
718
719 for (int i = 0 ; i < count; i++ ) {
720 Prop *prop = &mProps[i];
721 int16_t attrNameLen = strlen(prop->mName) + 1;
722 _INSERT(attrNameLen, sizeof(int16_t));
723 _INSERTSTRING(prop->mName, attrNameLen); // termination included
724 int8_t elemtype;
725 int16_t elemsize;
726 switch (prop->mType) {
727 case MediaAnalyticsItem::kTypeInt32:
728 {
729 elemtype = kInt32;
730 _INSERT(elemtype, sizeof(int8_t));
731 elemsize = sizeof(int32_t);
732 _INSERT(elemsize, sizeof(int16_t));
733
734 _INSERT(prop->u.int32Value, sizeof(int32_t));
735 break;
736 }
737 case MediaAnalyticsItem::kTypeInt64:
738 {
739 elemtype = kInt64;
740 _INSERT(elemtype, sizeof(int8_t));
741 elemsize = sizeof(int64_t);
742 _INSERT(elemsize, sizeof(int16_t));
743
744 _INSERT(prop->u.int64Value, sizeof(int64_t));
745 break;
746 }
747 case MediaAnalyticsItem::kTypeDouble:
748 {
749 elemtype = kDouble;
750 _INSERT(elemtype, sizeof(int8_t));
751 elemsize = sizeof(double);
752 _INSERT(elemsize, sizeof(int16_t));
753
754 _INSERT(prop->u.doubleValue, sizeof(double));
755 break;
756 }
757 case MediaAnalyticsItem::kTypeRate:
758 {
759 elemtype = kRate;
760 _INSERT(elemtype, sizeof(int8_t));
761 elemsize = 2 * sizeof(uint64_t);
762 _INSERT(elemsize, sizeof(int16_t));
763
764 _INSERT(prop->u.rate.count, sizeof(uint64_t));
765 _INSERT(prop->u.rate.duration, sizeof(uint64_t));
766 break;
767 }
768 case MediaAnalyticsItem::kTypeCString:
769 {
770 elemtype = kCString;
771 _INSERT(elemtype, sizeof(int8_t));
772 elemsize = strlen(prop->u.CStringValue) + 1;
773 _INSERT(elemsize, sizeof(int16_t));
774
775 _INSERTSTRING(prop->u.CStringValue, elemsize);
776 break;
777 }
778 default:
779 // error if can't encode; warning if can't decode
780 ALOGE("found bad Prop type: %d, idx %d, name %s",
781 prop->mType, i, prop->mName);
782 goto badness;
783 }
784 }
785
786 if (build + goal != filling) {
787 ALOGE("problems populating; wrote=%d planned=%d",
788 (int)(filling-build), goal);
789 goto badness;
790 }
791
792 *pbuffer = build;
793 *plength = goal;
794
795 return true;
796
797 badness:
798 free(build);
799 return false;
800}
801
Andy Hungaeef7882019-10-18 15:18:14 -0700802void MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
803{
804 data->writeCString(mName);
805 data->writeInt32(mType);
806 switch (mType) {
807 case kTypeInt32:
808 data->writeInt32(u.int32Value);
809 break;
810 case kTypeInt64:
811 data->writeInt64(u.int64Value);
812 break;
813 case kTypeDouble:
814 data->writeDouble(u.doubleValue);
815 break;
816 case kTypeRate:
817 data->writeInt64(u.rate.count);
818 data->writeInt64(u.rate.duration);
819 break;
820 case kTypeCString:
821 data->writeCString(u.CStringValue);
822 break;
823 default:
824 ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
825 break;
826 }
827}
828
829void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const {
830 switch (mType) {
831 case kTypeInt32:
832 snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
833 break;
834 case MediaAnalyticsItem::kTypeInt64:
835 snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value);
836 break;
837 case MediaAnalyticsItem::kTypeDouble:
838 snprintf(buffer, length, "%s=%e:", mName, u.doubleValue);
839 break;
840 case MediaAnalyticsItem::kTypeRate:
841 snprintf(buffer, length, "%s=%lld/%lld:",
842 mName, (long long)u.rate.count, (long long)u.rate.duration);
843 break;
844 case MediaAnalyticsItem::kTypeCString:
845 // TODO sanitize string for ':' '='
846 snprintf(buffer, length, "%s=%s:", mName, u.CStringValue);
847 break;
848 default:
849 ALOGE("%s: bad item type: %d for %s", __func__, mType, mName);
850 if (length > 0) buffer[0] = 0;
851 break;
852 }
853}
854
Ray Essick3938dc62016-11-01 08:56:56 -0700855} // namespace android
856