blob: c8713bfa1a12b5ff33d3ab96a607d0666e576c9d [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
Ray Essickba8c4842019-01-18 11:35:33 -080055// So caller doesn't need to know size of allocated space
56MediaAnalyticsItem *MediaAnalyticsItem::create()
57{
58 return MediaAnalyticsItem::create(kKeyNone);
59}
60
61MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
62{
63 MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
64 return item;
65}
Ray Essick3938dc62016-11-01 08:56:56 -070066
Ray Essickbf536ac2019-08-26 11:04:28 -070067MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
68 MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
69 return item;
70}
71
72mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
73 mediametrics_handle_t handle = (mediametrics_handle_t) item;
74 return handle;
75}
76
Ray Essick3938dc62016-11-01 08:56:56 -070077// access functions for the class
78MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080079 : mPid(-1),
80 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070081 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070082 mSessionID(MediaAnalyticsItem::SessionIDNone),
83 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080084 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080085 mPropCount(0), mPropSize(0), mProps(NULL)
86{
Ray Essick3938dc62016-11-01 08:56:56 -070087 mKey = MediaAnalyticsItem::kKeyNone;
88}
89
90MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080091 : mPid(-1),
92 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070093 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070094 mSessionID(MediaAnalyticsItem::SessionIDNone),
95 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080096 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080097 mPropCount(0), mPropSize(0), mProps(NULL)
98{
99 if (DEBUG_ALLOCATIONS) {
100 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
101 }
Ray Essick3938dc62016-11-01 08:56:56 -0700102 mKey = key;
103}
104
105MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800106 if (DEBUG_ALLOCATIONS) {
107 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
108 }
Ray Essick3938dc62016-11-01 08:56:56 -0700109 clear();
110}
111
Ray Essickb5fac8e2016-12-12 11:33:56 -0800112void MediaAnalyticsItem::clear() {
113
114 // clean allocated storage from key
115 mKey.clear();
116
Ray Essickd38e1742017-01-23 15:17:06 -0800117 // clean various major parameters
118 mSessionID = MediaAnalyticsItem::SessionIDNone;
119
Ray Essickb5fac8e2016-12-12 11:33:56 -0800120 // clean attributes
121 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700122 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800123 clearProp(&mProps[i]);
124 }
125 // the attribute records themselves
126 if (mProps != NULL) {
127 free(mProps);
128 mProps = NULL;
129 }
130 mPropSize = 0;
131 mPropCount = 0;
132
133 return;
134}
135
136// make a deep copy of myself
137MediaAnalyticsItem *MediaAnalyticsItem::dup() {
138 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
139
140 if (dst != NULL) {
141 // key as part of constructor
142 dst->mPid = this->mPid;
143 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700144 dst->mPkgName = this->mPkgName;
145 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800146 dst->mSessionID = this->mSessionID;
147 dst->mTimestamp = this->mTimestamp;
148 dst->mFinalized = this->mFinalized;
149
150 // properties aka attributes
151 dst->growProps(this->mPropCount);
152 for(size_t i=0;i<mPropCount;i++) {
153 copyProp(&dst->mProps[i], &this->mProps[i]);
154 }
155 dst->mPropCount = this->mPropCount;
156 }
157
158 return dst;
159}
160
Ray Essick3938dc62016-11-01 08:56:56 -0700161MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
162 mSessionID = id;
163 return *this;
164}
165
166MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
167 return mSessionID;
168}
169
170MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700171
172 if (mSessionID == SessionIDNone) {
173 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800174 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700175 sp<IMediaAnalyticsService> svc = getInstance();
176 if (svc != NULL) {
177 newid = svc->generateUniqueSessionID();
178 }
179 mSessionID = newid;
180 }
181
182 return mSessionID;
183}
184
185MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
186 mSessionID = MediaAnalyticsItem::SessionIDNone;
187 return *this;
188}
189
190MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
191 mTimestamp = ts;
192 return *this;
193}
194
195nsecs_t MediaAnalyticsItem::getTimestamp() const {
196 return mTimestamp;
197}
198
199MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
200 mPid = pid;
201 return *this;
202}
203
204pid_t MediaAnalyticsItem::getPid() const {
205 return mPid;
206}
207
208MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
209 mUid = uid;
210 return *this;
211}
212
213uid_t MediaAnalyticsItem::getUid() const {
214 return mUid;
215}
216
Ray Essick783bd0d2018-01-11 11:10:35 -0800217MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700218 mPkgName = pkgName;
219 return *this;
220}
221
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800222MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700223 mPkgVersionCode = pkgVersionCode;
224 return *this;
225}
226
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800227int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700228 return mPkgVersionCode;
229}
230
Ray Essickb5fac8e2016-12-12 11:33:56 -0800231// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700232MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700233 mKey = key;
234 return *this;
235}
236
Ray Essickb5fac8e2016-12-12 11:33:56 -0800237// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700238int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800239 return mPropCount;
240}
241
242// find the proper entry in the list
243size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
244{
245 size_t i = 0;
246 for (; i < mPropCount; i++) {
247 Prop *prop = &mProps[i];
248 if (prop->mNameLen != len) {
249 continue;
250 }
251 if (memcmp(name, prop->mName, len) == 0) {
252 break;
253 }
254 }
255 return i;
256}
257
258MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
259 size_t len = strlen(name);
260 size_t i = findPropIndex(name, len);
261 if (i < mPropCount) {
262 return &mProps[i];
263 }
264 return NULL;
265}
266
267void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700268 free((void *)mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800269 mName = (const char *) malloc(len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700270 LOG_ALWAYS_FATAL_IF(mName == NULL,
271 "failed malloc() for property '%s' (len %zu)",
272 name, len);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800273 memcpy ((void *)mName, name, len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700274 mNameLen = len;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800275}
276
Ray Essick9ce18f72018-05-07 15:54:30 -0700277// consider this "find-or-allocate".
278// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800279MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
280 size_t len = strlen(name);
281 size_t i = findPropIndex(name, len);
282 Prop *prop;
283
284 if (i < mPropCount) {
285 prop = &mProps[i];
286 } else {
287 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700288 if (growProps() == false) {
289 ALOGE("failed allocation for new props");
290 return NULL;
291 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800292 }
293 i = mPropCount++;
294 prop = &mProps[i];
295 prop->setName(name, len);
296 }
297
298 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700299}
300
Ray Essickf65f4212017-08-31 11:41:19 -0700301// used within the summarizers; return whether property existed
302bool MediaAnalyticsItem::removeProp(const char *name) {
303 size_t len = strlen(name);
304 size_t i = findPropIndex(name, len);
305 if (i < mPropCount) {
306 Prop *prop = &mProps[i];
307 clearProp(prop);
308 if (i != mPropCount-1) {
309 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700310 copyProp(prop, &mProps[mPropCount-1]);
311 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700312 }
313 mPropCount--;
314 return true;
315 }
316 return false;
317}
318
Ray Essick3938dc62016-11-01 08:56:56 -0700319// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800320void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
321 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700322 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700323 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700324 prop->mType = kTypeInt32;
325 prop->u.int32Value = value;
326 }
Ray Essick3938dc62016-11-01 08:56:56 -0700327}
328
Ray Essickb5fac8e2016-12-12 11:33:56 -0800329void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
330 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700331 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700332 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700333 prop->mType = kTypeInt64;
334 prop->u.int64Value = value;
335 }
Ray Essick3938dc62016-11-01 08:56:56 -0700336}
337
Ray Essickb5fac8e2016-12-12 11:33:56 -0800338void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
339 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700340 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700341 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700342 prop->mType = kTypeDouble;
343 prop->u.doubleValue = value;
344 }
Ray Essick3938dc62016-11-01 08:56:56 -0700345}
346
Ray Essickb5fac8e2016-12-12 11:33:56 -0800347void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
348
349 Prop *prop = allocateProp(name);
350 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700351 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700352 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700353 prop->mType = kTypeCString;
354 prop->u.CStringValue = strdup(value);
355 }
Ray Essick3938dc62016-11-01 08:56:56 -0700356}
357
Ray Essickb5fac8e2016-12-12 11:33:56 -0800358void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
359 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700360 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700361 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700362 prop->mType = kTypeRate;
363 prop->u.rate.count = count;
364 prop->u.rate.duration = duration;
365 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800366}
367
368
Ray Essick3938dc62016-11-01 08:56:56 -0700369// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800370void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
371 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700372 if (prop == NULL) {
373 return;
374 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800375 switch (prop->mType) {
376 case kTypeInt32:
377 prop->u.int32Value += value;
378 break;
379 default:
380 clearPropValue(prop);
381 prop->mType = kTypeInt32;
382 prop->u.int32Value = value;
383 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700384 }
Ray Essick3938dc62016-11-01 08:56:56 -0700385}
386
Ray Essickb5fac8e2016-12-12 11:33:56 -0800387void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
388 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700389 if (prop == NULL) {
390 return;
391 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800392 switch (prop->mType) {
393 case kTypeInt64:
394 prop->u.int64Value += value;
395 break;
396 default:
397 clearPropValue(prop);
398 prop->mType = kTypeInt64;
399 prop->u.int64Value = value;
400 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700401 }
Ray Essick3938dc62016-11-01 08:56:56 -0700402}
403
Ray Essickb5fac8e2016-12-12 11:33:56 -0800404void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
405 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700406 if (prop == NULL) {
407 return;
408 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800409 switch (prop->mType) {
410 case kTypeRate:
411 prop->u.rate.count += count;
412 prop->u.rate.duration += duration;
413 break;
414 default:
415 clearPropValue(prop);
416 prop->mType = kTypeRate;
417 prop->u.rate.count = count;
418 prop->u.rate.duration = duration;
419 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700420 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800421}
422
423void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
424 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700425 if (prop == NULL) {
426 return;
427 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800428 switch (prop->mType) {
429 case kTypeDouble:
430 prop->u.doubleValue += value;
431 break;
432 default:
433 clearPropValue(prop);
434 prop->mType = kTypeDouble;
435 prop->u.doubleValue = value;
436 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700437 }
Ray Essick3938dc62016-11-01 08:56:56 -0700438}
439
440// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800441bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
442 Prop *prop = findProp(name);
443 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700444 return false;
445 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800446 if (value != NULL) {
447 *value = prop->u.int32Value;
448 }
Ray Essick3938dc62016-11-01 08:56:56 -0700449 return true;
450}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800451
452bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
453 Prop *prop = findProp(name);
454 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700455 return false;
456 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800457 if (value != NULL) {
458 *value = prop->u.int64Value;
459 }
Ray Essick3938dc62016-11-01 08:56:56 -0700460 return true;
461}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800462
463bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
464 Prop *prop = findProp(name);
465 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700466 return false;
467 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800468 if (count != NULL) {
469 *count = prop->u.rate.count;
470 }
471 if (duration != NULL) {
472 *duration = prop->u.rate.duration;
473 }
474 if (rate != NULL) {
475 double r = 0.0;
476 if (prop->u.rate.duration != 0) {
477 r = prop->u.rate.count / (double) prop->u.rate.duration;
478 }
479 *rate = r;
480 }
481 return true;
482}
483
484bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
485 Prop *prop = findProp(name);
486 if (prop == NULL || prop->mType != kTypeDouble) {
487 return false;
488 }
489 if (value != NULL) {
490 *value = prop->u.doubleValue;
491 }
Ray Essick3938dc62016-11-01 08:56:56 -0700492 return true;
493}
494
495// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800496bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
497 Prop *prop = findProp(name);
Ray Essick9db7b812018-11-15 12:42:19 -0800498 if (prop == NULL || prop->mType != kTypeCString) {
Ray Essick3938dc62016-11-01 08:56:56 -0700499 return false;
500 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800501 if (value != NULL) {
502 *value = strdup(prop->u.CStringValue);
503 }
Ray Essick3938dc62016-11-01 08:56:56 -0700504 return true;
505}
506
Ray Essick20147322018-11-17 09:08:39 -0800507bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
508 Prop *prop = findProp(name);
509 if (prop == NULL || prop->mType != kTypeCString) {
510 return false;
511 }
512 if (value != NULL) {
513 // std::string makes a copy for us
514 *value = prop->u.CStringValue;
515 }
516 return true;
517}
518
Ray Essick3938dc62016-11-01 08:56:56 -0700519// remove indicated keys and their values
520// return value is # keys removed
521int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
522 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800523 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700524 return -1;
525 }
526 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800527 const char *name = attrs[i];
528 size_t len = strlen(name);
529 size_t j = findPropIndex(name, len);
530 if (j >= mPropCount) {
531 // not there
532 continue;
533 } else if (j+1 == mPropCount) {
534 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700535 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800536 clearProp(&mProps[j]);
537 mPropCount--;
538 } else {
539 // in the middle, bring last one down and shorten
540 zapped++;
541 clearProp(&mProps[j]);
542 mProps[j] = mProps[mPropCount-1];
543 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700544 }
545 }
546 return zapped;
547}
548
549// remove any keys NOT in the provided list
550// return value is # keys removed
551int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
552 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800553 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700554 return -1;
555 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800556 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
557 Prop *prop = &mProps[i];
558 for (ssize_t j = 0; j < n ; j++) {
559 if (strcmp(prop->mName, attrs[j]) == 0) {
560 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700561 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800562 if (i != (ssize_t)(mPropCount-1)) {
563 *prop = mProps[mPropCount-1];
564 }
565 initProp(&mProps[mPropCount-1]);
566 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700567 break;
568 }
569 }
570 }
571 return zapped;
572}
573
574// remove a single key
575// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800576int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
577 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700578}
579
Ray Essick3938dc62016-11-01 08:56:56 -0700580// handle individual items/properties stored within the class
581//
Ray Essick3938dc62016-11-01 08:56:56 -0700582
Ray Essickb5fac8e2016-12-12 11:33:56 -0800583void MediaAnalyticsItem::initProp(Prop *prop) {
584 if (prop != NULL) {
585 prop->mName = NULL;
586 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700587
Ray Essickb5fac8e2016-12-12 11:33:56 -0800588 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700589 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800590}
591
592void MediaAnalyticsItem::clearProp(Prop *prop)
593{
594 if (prop != NULL) {
595 if (prop->mName != NULL) {
596 free((void *)prop->mName);
597 prop->mName = NULL;
598 prop->mNameLen = 0;
599 }
600
601 clearPropValue(prop);
602 }
603}
604
605void MediaAnalyticsItem::clearPropValue(Prop *prop)
606{
607 if (prop != NULL) {
608 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
609 free(prop->u.CStringValue);
610 prop->u.CStringValue = NULL;
611 }
612 prop->mType = kTypeNone;
613 }
614}
615
616void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
617{
618 // get rid of any pointers in the dst
619 clearProp(dst);
620
621 *dst = *src;
622
623 // fix any pointers that we blindly copied, so we have our own copies
624 if (dst->mName) {
625 void *p = malloc(dst->mNameLen + 1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700626 LOG_ALWAYS_FATAL_IF(p == NULL,
627 "failed malloc() duping property '%s' (len %zu)",
628 dst->mName, dst->mNameLen);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800629 memcpy (p, src->mName, dst->mNameLen + 1);
630 dst->mName = (const char *) p;
631 }
632 if (dst->mType == kTypeCString) {
633 dst->u.CStringValue = strdup(src->u.CStringValue);
634 }
635}
636
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700637bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800638{
639 if (increment <= 0) {
640 increment = kGrowProps;
641 }
642 int nsize = mPropSize + increment;
643 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
644
645 if (ni != NULL) {
646 for (int i = mPropSize; i < nsize; i++) {
647 initProp(&ni[i]);
648 }
649 mProps = ni;
650 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700651 return true;
652 } else {
653 ALOGW("MediaAnalyticsItem::growProps fails");
654 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800655 }
Ray Essick3938dc62016-11-01 08:56:56 -0700656}
657
658// Parcel / serialize things for binder calls
659//
660
661int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800662 int32_t version = data.readInt32();
663
664 switch(version) {
665 case 0:
666 return readFromParcel0(data);
667 break;
668 default:
669 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
670 return -1;
671 }
672}
673
674int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700675 // into 'this' object
676 // .. we make a copy of the string to put away.
677 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700678 mPid = data.readInt32();
679 mUid = data.readInt32();
680 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800681 mPkgVersionCode = data.readInt64();
Ray Essick3938dc62016-11-01 08:56:56 -0700682 mSessionID = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800683 // We no longer pay attention to user setting of finalized, BUT it's
684 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700685 mFinalized = data.readInt32();
Ray Essick92d23b42018-01-29 12:10:30 -0800686 mFinalized = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700687 mTimestamp = data.readInt64();
688
689 int count = data.readInt32();
690 for (int i = 0; i < count ; i++) {
691 MediaAnalyticsItem::Attr attr = data.readCString();
692 int32_t ztype = data.readInt32();
693 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800694 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700695 setInt32(attr, data.readInt32());
696 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800697 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700698 setInt64(attr, data.readInt64());
699 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800700 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700701 setDouble(attr, data.readDouble());
702 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800703 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700704 setCString(attr, data.readCString());
705 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800706 case MediaAnalyticsItem::kTypeRate:
707 {
708 int64_t count = data.readInt64();
709 int64_t duration = data.readInt64();
710 setRate(attr, count, duration);
711 }
712 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700713 default:
714 ALOGE("reading bad item type: %d, idx %d",
715 ztype, i);
716 return -1;
717 }
718 }
719
720 return 0;
721}
722
723int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
Ray Essickba8c4842019-01-18 11:35:33 -0800724
Ray Essick3938dc62016-11-01 08:56:56 -0700725 if (data == NULL) return -1;
726
Ray Essickba8c4842019-01-18 11:35:33 -0800727 int32_t version = 0;
728 data->writeInt32(version);
729
730 switch(version) {
731 case 0:
732 return writeToParcel0(data);
733 break;
734 default:
735 ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
736 return -1;
737 }
738}
739
740int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
Ray Essick3938dc62016-11-01 08:56:56 -0700741
742 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700743 data->writeInt32(mPid);
744 data->writeInt32(mUid);
745 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800746 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700747 data->writeInt64(mSessionID);
748 data->writeInt32(mFinalized);
749 data->writeInt64(mTimestamp);
750
751 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800752 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700753 data->writeInt32(count);
754 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800755 Prop *prop = &mProps[i];
756 data->writeCString(prop->mName);
757 data->writeInt32(prop->mType);
758 switch (prop->mType) {
759 case MediaAnalyticsItem::kTypeInt32:
760 data->writeInt32(prop->u.int32Value);
761 break;
762 case MediaAnalyticsItem::kTypeInt64:
763 data->writeInt64(prop->u.int64Value);
764 break;
765 case MediaAnalyticsItem::kTypeDouble:
766 data->writeDouble(prop->u.doubleValue);
767 break;
768 case MediaAnalyticsItem::kTypeRate:
769 data->writeInt64(prop->u.rate.count);
770 data->writeInt64(prop->u.rate.duration);
771 break;
772 case MediaAnalyticsItem::kTypeCString:
773 data->writeCString(prop->u.CStringValue);
774 break;
775 default:
776 ALOGE("found bad Prop type: %d, idx %d, name %s",
777 prop->mType, i, prop->mName);
778 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700779 }
780 }
781
782 return 0;
783}
784
Ray Essick20147322018-11-17 09:08:39 -0800785const char *MediaAnalyticsItem::toCString() {
786 return toCString(PROTO_LAST);
787}
788
789const char * MediaAnalyticsItem::toCString(int version) {
790 std::string val = toString(version);
791 return strdup(val.c_str());
792}
793
Andy Hung17dbaf22019-10-11 14:06:31 -0700794std::string MediaAnalyticsItem::toString() const {
Ray Essick5b77bd22018-01-23 16:11:06 -0800795 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700796}
Ray Essick3938dc62016-11-01 08:56:56 -0700797
Andy Hung17dbaf22019-10-11 14:06:31 -0700798std::string MediaAnalyticsItem::toString(int version) const {
Ray Essickf65f4212017-08-31 11:41:19 -0700799
800 // v0 : released with 'o'
801 // v1 : bug fix (missing pid/finalized separator),
802 // adds apk name, apk version code
803
804 if (version <= PROTO_FIRST) {
805 // default to original v0 format, until proper parsers are in place
806 version = PROTO_V0;
807 } else if (version > PROTO_LAST) {
808 version = PROTO_LAST;
809 }
810
Ray Essick783bd0d2018-01-11 11:10:35 -0800811 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800812 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700813
Ray Essickf65f4212017-08-31 11:41:19 -0700814 if (version == PROTO_V0) {
815 result = "(";
816 } else {
817 snprintf(buffer, sizeof(buffer), "[%d:", version);
818 result.append(buffer);
819 }
820
Ray Essick3938dc62016-11-01 08:56:56 -0700821 // same order as we spill into the parcel, although not required
822 // key+session are our primary matching criteria
823 result.append(mKey.c_str());
824 result.append(":");
825 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
826 result.append(buffer);
827
Ray Essickf65f4212017-08-31 11:41:19 -0700828 snprintf(buffer, sizeof(buffer), "%d:", mUid);
829 result.append(buffer);
830
831 if (version >= PROTO_V1) {
832 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800833 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700834 result.append(buffer);
835 }
836
837 // in 'o' (v1) , the separator between pid and finalized was omitted
838 if (version <= PROTO_V0) {
839 snprintf(buffer, sizeof(buffer), "%d", mPid);
840 } else {
841 snprintf(buffer, sizeof(buffer), "%d:", mPid);
842 }
Ray Essick3938dc62016-11-01 08:56:56 -0700843 result.append(buffer);
844
845 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
846 result.append(buffer);
847 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
848 result.append(buffer);
849
850 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800851 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700852 snprintf(buffer, sizeof(buffer), "%d:", count);
853 result.append(buffer);
854 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800855 Prop *prop = &mProps[i];
856 switch (prop->mType) {
857 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700858 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800859 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700860 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800861 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700862 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800863 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700864 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800865 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700866 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800867 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700868 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800869 case MediaAnalyticsItem::kTypeRate:
870 snprintf(buffer,sizeof(buffer),
871 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
872 prop->u.rate.count, prop->u.rate.duration);
873 break;
874 case MediaAnalyticsItem::kTypeCString:
875 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700876 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800877 // XXX: sanitize string for ':' '='
878 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700879 buffer[0] = ':';
880 buffer[1] = '\0';
881 break;
882 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800883 ALOGE("to_String bad item type: %d for %s",
884 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700885 break;
886 }
887 result.append(buffer);
888 }
889
Ray Essickf65f4212017-08-31 11:41:19 -0700890 if (version == PROTO_V0) {
891 result.append(")");
892 } else {
893 result.append("]");
894 }
Ray Essick3938dc62016-11-01 08:56:56 -0700895
896 return result;
897}
898
899// for the lazy, we offer methods that finds the service and
900// calls the appropriate daemon
901bool MediaAnalyticsItem::selfrecord() {
902 return selfrecord(false);
903}
904
905bool MediaAnalyticsItem::selfrecord(bool forcenew) {
906
Ray Essickb5fac8e2016-12-12 11:33:56 -0800907 if (DEBUG_API) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800908 std::string p = this->toString();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800909 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
910 }
Ray Essick3938dc62016-11-01 08:56:56 -0700911
912 sp<IMediaAnalyticsService> svc = getInstance();
913
914 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700915 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
916 if (newid == SessionIDInvalid) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800917 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700918 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
919 return false;
920 }
Ray Essick3938dc62016-11-01 08:56:56 -0700921 return true;
922 } else {
923 return false;
924 }
925}
926
927// get a connection we can reuse for most of our lifetime
928// static
929sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
930static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700931static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700932
933//static
934bool MediaAnalyticsItem::isEnabled() {
935 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
936
937 if (enabled == -1) {
938 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
939 }
940 if (enabled == -1) {
941 enabled = MediaAnalyticsItem::EnabledProperty_default;
942 }
943 if (enabled <= 0) {
944 return false;
945 }
946 return true;
947}
948
Ray Essick2ab3c432017-10-02 09:29:49 -0700949
950// monitor health of our connection to the metrics service
951class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
952 virtual void binderDied(const wp<IBinder> &) {
953 ALOGW("Reacquire service connection on next request");
954 MediaAnalyticsItem::dropInstance();
955 }
956};
957
958static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
959
960// static
961void MediaAnalyticsItem::dropInstance() {
962 Mutex::Autolock _l(sInitMutex);
963 remainingBindAttempts = SVC_TRIES;
964 sAnalyticsService = NULL;
965}
966
Ray Essick3938dc62016-11-01 08:56:56 -0700967//static
968sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700969
Ray Essickd38e1742017-01-23 15:17:06 -0800970 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700971 int enabled = isEnabled();
972
973 if (enabled == false) {
974 if (DEBUG_SERVICEACCESS) {
975 ALOGD("disabled");
976 }
977 return NULL;
978 }
979
Ray Essick79a89ef2017-04-24 15:52:54 -0700980 // completely skip logging from certain UIDs. We do this here
981 // to avoid the multi-second timeouts while we learn that
982 // sepolicy will not let us find the service.
983 // We do this only for a select set of UIDs
984 // The sepolicy protection is still in place, we just want a faster
985 // response from this specific, small set of uids.
986 {
987 uid_t uid = getuid();
988 switch (uid) {
989 case AID_RADIO: // telephony subsystem, RIL
990 return NULL;
991 break;
992 default:
993 // let sepolicy deny access if appropriate
994 break;
995 }
996 }
997
Ray Essick3938dc62016-11-01 08:56:56 -0700998 {
999 Mutex::Autolock _l(sInitMutex);
1000 const char *badness = "";
1001
Ray Essick2ab3c432017-10-02 09:29:49 -07001002 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -08001003 // (1) we haven't tried to initialize it yet
1004 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -07001005 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -07001006 sp<IServiceManager> sm = defaultServiceManager();
1007 if (sm != NULL) {
1008 sp<IBinder> binder = sm->getService(String16(servicename));
1009 if (binder != NULL) {
1010 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -07001011 if (sNotifier != NULL) {
1012 sNotifier = NULL;
1013 }
1014 sNotifier = new MediaMetricsDeathNotifier();
1015 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -07001016 } else {
1017 badness = "did not find service";
1018 }
1019 } else {
1020 badness = "No Service Manager access";
1021 }
Ray Essickb5fac8e2016-12-12 11:33:56 -08001022
1023 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -07001024 if (remainingBindAttempts > 0) {
1025 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -08001026 }
1027 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -07001028 ALOGD("Unable to bind to service %s: %s", servicename, badness);
1029 }
1030 }
1031 }
Ray Essickb5fac8e2016-12-12 11:33:56 -08001032
Ray Essick3938dc62016-11-01 08:56:56 -07001033 return sAnalyticsService;
1034 }
1035}
1036
Ray Essick3938dc62016-11-01 08:56:56 -07001037// merge the info from 'incoming' into this record.
1038// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -08001039bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -07001040
1041 // if I don't have key or session id, take them from incoming
1042 // 'this' should never be missing both of them...
1043 if (mKey.empty()) {
1044 mKey = incoming->mKey;
1045 } else if (mSessionID == 0) {
1046 mSessionID = incoming->mSessionID;
1047 }
1048
Ray Essick3938dc62016-11-01 08:56:56 -07001049 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -08001050 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -07001051 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -08001052 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -08001053 const char *p = iprop->mName;
1054 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001055
1056 // should ignore a zero length name...
1057 if (len == 0) {
1058 continue;
1059 }
1060
1061 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -07001062
Ray Essickb5fac8e2016-12-12 11:33:56 -08001063 if (oprop == NULL) {
1064 // no oprop, so we insert the new one
1065 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001066 if (oprop != NULL) {
1067 copyProp(oprop, iprop);
1068 } else {
1069 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -08001070 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001071 } else {
1072 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -07001073 }
1074 }
1075
1076 // not sure when we'd return false...
1077 return true;
1078}
1079
Ray Essickba8c4842019-01-18 11:35:33 -08001080// a byte array; contents are
1081// overall length (uint32) including the length field itself
1082// encoding version (uint32)
1083// count of properties (uint32)
1084// N copies of:
1085// property name as length(int16), bytes
1086// the bytes WILL include the null terminator of the name
1087// type (uint8 -- 1 byte)
1088// size of value field (int16 -- 2 bytes)
1089// value (size based on type)
1090// int32, int64, double -- little endian 4/8/8 bytes respectively
1091// cstring -- N bytes of value [WITH terminator]
1092
1093enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
1094
1095bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
1096
1097 char *build = NULL;
1098
1099 if (pbuffer == NULL || plength == NULL)
1100 return false;
1101
1102 // consistency for the caller, who owns whatever comes back in this pointer.
1103 *pbuffer = NULL;
1104
1105 // first, let's calculate sizes
1106 int32_t goal = 0;
1107 int32_t version = 0;
1108
1109 goal += sizeof(uint32_t); // overall length, including the length field
1110 goal += sizeof(uint32_t); // encoding version
1111 goal += sizeof(uint32_t); // # properties
1112
1113 int32_t count = mPropCount;
1114 for (int i = 0 ; i < count; i++ ) {
1115 Prop *prop = &mProps[i];
1116 goal += sizeof(uint16_t); // name length
1117 goal += strlen(prop->mName) + 1; // string + null
1118 goal += sizeof(uint8_t); // type
1119 goal += sizeof(uint16_t); // size of value
1120 switch (prop->mType) {
1121 case MediaAnalyticsItem::kTypeInt32:
1122 goal += sizeof(uint32_t);
1123 break;
1124 case MediaAnalyticsItem::kTypeInt64:
1125 goal += sizeof(uint64_t);
1126 break;
1127 case MediaAnalyticsItem::kTypeDouble:
1128 goal += sizeof(double);
1129 break;
1130 case MediaAnalyticsItem::kTypeRate:
1131 goal += 2 * sizeof(uint64_t);
1132 break;
1133 case MediaAnalyticsItem::kTypeCString:
1134 // length + actual string + null
1135 goal += strlen(prop->u.CStringValue) + 1;
1136 break;
1137 default:
1138 ALOGE("found bad Prop type: %d, idx %d, name %s",
1139 prop->mType, i, prop->mName);
1140 return false;
1141 }
1142 }
1143
1144 // now that we have a size... let's allocate and fill
1145 build = (char *)malloc(goal);
1146 if (build == NULL)
1147 return false;
1148
1149 memset(build, 0, goal);
1150
1151 char *filling = build;
1152
1153#define _INSERT(val, size) \
1154 { memcpy(filling, &(val), (size)); filling += (size);}
1155#define _INSERTSTRING(val, size) \
1156 { memcpy(filling, (val), (size)); filling += (size);}
1157
1158 _INSERT(goal, sizeof(int32_t));
1159 _INSERT(version, sizeof(int32_t));
1160 _INSERT(count, sizeof(int32_t));
1161
1162 for (int i = 0 ; i < count; i++ ) {
1163 Prop *prop = &mProps[i];
1164 int16_t attrNameLen = strlen(prop->mName) + 1;
1165 _INSERT(attrNameLen, sizeof(int16_t));
1166 _INSERTSTRING(prop->mName, attrNameLen); // termination included
1167 int8_t elemtype;
1168 int16_t elemsize;
1169 switch (prop->mType) {
1170 case MediaAnalyticsItem::kTypeInt32:
1171 {
1172 elemtype = kInt32;
1173 _INSERT(elemtype, sizeof(int8_t));
1174 elemsize = sizeof(int32_t);
1175 _INSERT(elemsize, sizeof(int16_t));
1176
1177 _INSERT(prop->u.int32Value, sizeof(int32_t));
1178 break;
1179 }
1180 case MediaAnalyticsItem::kTypeInt64:
1181 {
1182 elemtype = kInt64;
1183 _INSERT(elemtype, sizeof(int8_t));
1184 elemsize = sizeof(int64_t);
1185 _INSERT(elemsize, sizeof(int16_t));
1186
1187 _INSERT(prop->u.int64Value, sizeof(int64_t));
1188 break;
1189 }
1190 case MediaAnalyticsItem::kTypeDouble:
1191 {
1192 elemtype = kDouble;
1193 _INSERT(elemtype, sizeof(int8_t));
1194 elemsize = sizeof(double);
1195 _INSERT(elemsize, sizeof(int16_t));
1196
1197 _INSERT(prop->u.doubleValue, sizeof(double));
1198 break;
1199 }
1200 case MediaAnalyticsItem::kTypeRate:
1201 {
1202 elemtype = kRate;
1203 _INSERT(elemtype, sizeof(int8_t));
1204 elemsize = 2 * sizeof(uint64_t);
1205 _INSERT(elemsize, sizeof(int16_t));
1206
1207 _INSERT(prop->u.rate.count, sizeof(uint64_t));
1208 _INSERT(prop->u.rate.duration, sizeof(uint64_t));
1209 break;
1210 }
1211 case MediaAnalyticsItem::kTypeCString:
1212 {
1213 elemtype = kCString;
1214 _INSERT(elemtype, sizeof(int8_t));
1215 elemsize = strlen(prop->u.CStringValue) + 1;
1216 _INSERT(elemsize, sizeof(int16_t));
1217
1218 _INSERTSTRING(prop->u.CStringValue, elemsize);
1219 break;
1220 }
1221 default:
1222 // error if can't encode; warning if can't decode
1223 ALOGE("found bad Prop type: %d, idx %d, name %s",
1224 prop->mType, i, prop->mName);
1225 goto badness;
1226 }
1227 }
1228
1229 if (build + goal != filling) {
1230 ALOGE("problems populating; wrote=%d planned=%d",
1231 (int)(filling-build), goal);
1232 goto badness;
1233 }
1234
1235 *pbuffer = build;
1236 *plength = goal;
1237
1238 return true;
1239
1240 badness:
1241 free(build);
1242 return false;
1243}
1244
Ray Essick3938dc62016-11-01 08:56:56 -07001245} // namespace android
1246