blob: 448e2d9959aa2e889f68f1f9294b6b48dc143411 [file] [log] [blame]
Ray Essick3938dc62016-11-01 08:56:56 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#undef LOG_TAG
18#define LOG_TAG "MediaAnalyticsItem"
19
Ray Essick3938dc62016-11-01 08:56:56 -070020#include <inttypes.h>
Ray Essickb5fac8e2016-12-12 11:33:56 -080021#include <stdlib.h>
22#include <string.h>
23#include <sys/types.h>
Ray Essick3938dc62016-11-01 08:56:56 -070024
25#include <binder/Parcel.h>
26#include <utils/Errors.h>
27#include <utils/Log.h>
28#include <utils/Mutex.h>
Ray Essick3938dc62016-11-01 08:56:56 -070029#include <utils/SortedVector.h>
30#include <utils/threads.h>
31
Ray Essick3938dc62016-11-01 08:56:56 -070032#include <binder/IServiceManager.h>
33#include <media/IMediaAnalyticsService.h>
34#include <media/MediaAnalyticsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070035#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070036
37namespace android {
38
39#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080040#define DEBUG_API 0
41#define DEBUG_ALLOCATIONS 0
42
43// after this many failed attempts, we stop trying [from this process] and just say that
44// the service is off.
45#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070046
47// the few universal keys we have
48const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
49const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none";
50
Ray Essickd38e1742017-01-23 15:17:06 -080051const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled";
52const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
Ray Essickd6a6c672017-01-25 14:28:51 -080053const int MediaAnalyticsItem::EnabledProperty_default = 1;
Ray Essick3938dc62016-11-01 08:56:56 -070054
55
56// access functions for the class
57MediaAnalyticsItem::MediaAnalyticsItem()
Ray Essickd38e1742017-01-23 15:17:06 -080058 : mPid(-1),
59 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070060 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070061 mSessionID(MediaAnalyticsItem::SessionIDNone),
62 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080063 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080064 mPropCount(0), mPropSize(0), mProps(NULL)
65{
Ray Essick3938dc62016-11-01 08:56:56 -070066 mKey = MediaAnalyticsItem::kKeyNone;
67}
68
69MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
Ray Essickd38e1742017-01-23 15:17:06 -080070 : mPid(-1),
71 mUid(-1),
Ray Essickfa149562017-09-19 09:27:31 -070072 mPkgVersionCode(0),
Ray Essick3938dc62016-11-01 08:56:56 -070073 mSessionID(MediaAnalyticsItem::SessionIDNone),
74 mTimestamp(0),
Ray Essick92d23b42018-01-29 12:10:30 -080075 mFinalized(1),
Ray Essickb5fac8e2016-12-12 11:33:56 -080076 mPropCount(0), mPropSize(0), mProps(NULL)
77{
78 if (DEBUG_ALLOCATIONS) {
79 ALOGD("Allocate MediaAnalyticsItem @ %p", this);
80 }
Ray Essick3938dc62016-11-01 08:56:56 -070081 mKey = key;
82}
83
84MediaAnalyticsItem::~MediaAnalyticsItem() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080085 if (DEBUG_ALLOCATIONS) {
86 ALOGD("Destroy MediaAnalyticsItem @ %p", this);
87 }
Ray Essick3938dc62016-11-01 08:56:56 -070088 clear();
89}
90
Ray Essickb5fac8e2016-12-12 11:33:56 -080091void MediaAnalyticsItem::clear() {
92
93 // clean allocated storage from key
94 mKey.clear();
95
Ray Essickd38e1742017-01-23 15:17:06 -080096 // clean various major parameters
97 mSessionID = MediaAnalyticsItem::SessionIDNone;
98
Ray Essickb5fac8e2016-12-12 11:33:56 -080099 // clean attributes
100 // contents of the attributes
Ray Essick58f58732017-10-02 10:56:18 -0700101 for (size_t i = 0 ; i < mPropCount; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800102 clearProp(&mProps[i]);
103 }
104 // the attribute records themselves
105 if (mProps != NULL) {
106 free(mProps);
107 mProps = NULL;
108 }
109 mPropSize = 0;
110 mPropCount = 0;
111
112 return;
113}
114
115// make a deep copy of myself
116MediaAnalyticsItem *MediaAnalyticsItem::dup() {
117 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
118
119 if (dst != NULL) {
120 // key as part of constructor
121 dst->mPid = this->mPid;
122 dst->mUid = this->mUid;
Ray Essickf65f4212017-08-31 11:41:19 -0700123 dst->mPkgName = this->mPkgName;
124 dst->mPkgVersionCode = this->mPkgVersionCode;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800125 dst->mSessionID = this->mSessionID;
126 dst->mTimestamp = this->mTimestamp;
127 dst->mFinalized = this->mFinalized;
128
129 // properties aka attributes
130 dst->growProps(this->mPropCount);
131 for(size_t i=0;i<mPropCount;i++) {
132 copyProp(&dst->mProps[i], &this->mProps[i]);
133 }
134 dst->mPropCount = this->mPropCount;
135 }
136
137 return dst;
138}
139
Ray Essick3938dc62016-11-01 08:56:56 -0700140MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
141 mSessionID = id;
142 return *this;
143}
144
145MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
146 return mSessionID;
147}
148
149MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
Ray Essick3938dc62016-11-01 08:56:56 -0700150
151 if (mSessionID == SessionIDNone) {
152 // get one from the server
Ray Essickb5fac8e2016-12-12 11:33:56 -0800153 MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700154 sp<IMediaAnalyticsService> svc = getInstance();
155 if (svc != NULL) {
156 newid = svc->generateUniqueSessionID();
157 }
158 mSessionID = newid;
159 }
160
161 return mSessionID;
162}
163
164MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
165 mSessionID = MediaAnalyticsItem::SessionIDNone;
166 return *this;
167}
168
169MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
170 mTimestamp = ts;
171 return *this;
172}
173
174nsecs_t MediaAnalyticsItem::getTimestamp() const {
175 return mTimestamp;
176}
177
178MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
179 mPid = pid;
180 return *this;
181}
182
183pid_t MediaAnalyticsItem::getPid() const {
184 return mPid;
185}
186
187MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
188 mUid = uid;
189 return *this;
190}
191
192uid_t MediaAnalyticsItem::getUid() const {
193 return mUid;
194}
195
Ray Essick783bd0d2018-01-11 11:10:35 -0800196MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700197 mPkgName = pkgName;
198 return *this;
199}
200
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800201MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700202 mPkgVersionCode = pkgVersionCode;
203 return *this;
204}
205
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800206int64_t MediaAnalyticsItem::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700207 return mPkgVersionCode;
208}
209
Ray Essickb5fac8e2016-12-12 11:33:56 -0800210// this key is for the overall record -- "codec", "player", "drm", etc
Ray Essick3938dc62016-11-01 08:56:56 -0700211MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
Ray Essick3938dc62016-11-01 08:56:56 -0700212 mKey = key;
213 return *this;
214}
215
216MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
217 return mKey;
218}
219
Ray Essickb5fac8e2016-12-12 11:33:56 -0800220// number of attributes we have in this record
Ray Essick3938dc62016-11-01 08:56:56 -0700221int32_t MediaAnalyticsItem::count() const {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800222 return mPropCount;
223}
224
225// find the proper entry in the list
226size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
227{
228 size_t i = 0;
229 for (; i < mPropCount; i++) {
230 Prop *prop = &mProps[i];
231 if (prop->mNameLen != len) {
232 continue;
233 }
234 if (memcmp(name, prop->mName, len) == 0) {
235 break;
236 }
237 }
238 return i;
239}
240
241MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
242 size_t len = strlen(name);
243 size_t i = findPropIndex(name, len);
244 if (i < mPropCount) {
245 return &mProps[i];
246 }
247 return NULL;
248}
249
250void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700251 free((void *)mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800252 mName = (const char *) malloc(len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700253 LOG_ALWAYS_FATAL_IF(mName == NULL,
254 "failed malloc() for property '%s' (len %zu)",
255 name, len);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800256 memcpy ((void *)mName, name, len+1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700257 mNameLen = len;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800258}
259
Ray Essick9ce18f72018-05-07 15:54:30 -0700260// consider this "find-or-allocate".
261// caller validates type and uses clearPropValue() accordingly
Ray Essickb5fac8e2016-12-12 11:33:56 -0800262MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
263 size_t len = strlen(name);
264 size_t i = findPropIndex(name, len);
265 Prop *prop;
266
267 if (i < mPropCount) {
268 prop = &mProps[i];
269 } else {
270 if (i == mPropSize) {
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700271 if (growProps() == false) {
272 ALOGE("failed allocation for new props");
273 return NULL;
274 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800275 }
276 i = mPropCount++;
277 prop = &mProps[i];
278 prop->setName(name, len);
279 }
280
281 return prop;
Ray Essick3938dc62016-11-01 08:56:56 -0700282}
283
Ray Essickf65f4212017-08-31 11:41:19 -0700284// used within the summarizers; return whether property existed
285bool MediaAnalyticsItem::removeProp(const char *name) {
286 size_t len = strlen(name);
287 size_t i = findPropIndex(name, len);
288 if (i < mPropCount) {
289 Prop *prop = &mProps[i];
290 clearProp(prop);
291 if (i != mPropCount-1) {
292 // in the middle, bring last one down to fill gap
Ray Essick58f58732017-10-02 10:56:18 -0700293 copyProp(prop, &mProps[mPropCount-1]);
294 clearProp(&mProps[mPropCount-1]);
Ray Essickf65f4212017-08-31 11:41:19 -0700295 }
296 mPropCount--;
297 return true;
298 }
299 return false;
300}
301
Ray Essick3938dc62016-11-01 08:56:56 -0700302// set the values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800303void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
304 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700305 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700306 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700307 prop->mType = kTypeInt32;
308 prop->u.int32Value = value;
309 }
Ray Essick3938dc62016-11-01 08:56:56 -0700310}
311
Ray Essickb5fac8e2016-12-12 11:33:56 -0800312void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
313 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700314 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700315 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700316 prop->mType = kTypeInt64;
317 prop->u.int64Value = value;
318 }
Ray Essick3938dc62016-11-01 08:56:56 -0700319}
320
Ray Essickb5fac8e2016-12-12 11:33:56 -0800321void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
322 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700323 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700324 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700325 prop->mType = kTypeDouble;
326 prop->u.doubleValue = value;
327 }
Ray Essick3938dc62016-11-01 08:56:56 -0700328}
329
Ray Essickb5fac8e2016-12-12 11:33:56 -0800330void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
331
332 Prop *prop = allocateProp(name);
333 // any old value will be gone
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700334 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700335 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700336 prop->mType = kTypeCString;
337 prop->u.CStringValue = strdup(value);
338 }
Ray Essick3938dc62016-11-01 08:56:56 -0700339}
340
Ray Essickb5fac8e2016-12-12 11:33:56 -0800341void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
342 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700343 if (prop != NULL) {
Ray Essick9ce18f72018-05-07 15:54:30 -0700344 clearPropValue(prop);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700345 prop->mType = kTypeRate;
346 prop->u.rate.count = count;
347 prop->u.rate.duration = duration;
348 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800349}
350
351
Ray Essick3938dc62016-11-01 08:56:56 -0700352// find/add/set fused into a single operation
Ray Essickb5fac8e2016-12-12 11:33:56 -0800353void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
354 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700355 if (prop == NULL) {
356 return;
357 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800358 switch (prop->mType) {
359 case kTypeInt32:
360 prop->u.int32Value += value;
361 break;
362 default:
363 clearPropValue(prop);
364 prop->mType = kTypeInt32;
365 prop->u.int32Value = value;
366 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700367 }
Ray Essick3938dc62016-11-01 08:56:56 -0700368}
369
Ray Essickb5fac8e2016-12-12 11:33:56 -0800370void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_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 kTypeInt64:
377 prop->u.int64Value += value;
378 break;
379 default:
380 clearPropValue(prop);
381 prop->mType = kTypeInt64;
382 prop->u.int64Value = 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::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
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 kTypeRate:
394 prop->u.rate.count += count;
395 prop->u.rate.duration += duration;
396 break;
397 default:
398 clearPropValue(prop);
399 prop->mType = kTypeRate;
400 prop->u.rate.count = count;
401 prop->u.rate.duration = duration;
402 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700403 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800404}
405
406void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
407 Prop *prop = allocateProp(name);
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700408 if (prop == NULL) {
409 return;
410 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800411 switch (prop->mType) {
412 case kTypeDouble:
413 prop->u.doubleValue += value;
414 break;
415 default:
416 clearPropValue(prop);
417 prop->mType = kTypeDouble;
418 prop->u.doubleValue = value;
419 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700420 }
Ray Essick3938dc62016-11-01 08:56:56 -0700421}
422
423// find & extract values
Ray Essickb5fac8e2016-12-12 11:33:56 -0800424bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
425 Prop *prop = findProp(name);
426 if (prop == NULL || prop->mType != kTypeInt32) {
Ray Essick3938dc62016-11-01 08:56:56 -0700427 return false;
428 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800429 if (value != NULL) {
430 *value = prop->u.int32Value;
431 }
Ray Essick3938dc62016-11-01 08:56:56 -0700432 return true;
433}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800434
435bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
436 Prop *prop = findProp(name);
437 if (prop == NULL || prop->mType != kTypeInt64) {
Ray Essick3938dc62016-11-01 08:56:56 -0700438 return false;
439 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800440 if (value != NULL) {
441 *value = prop->u.int64Value;
442 }
Ray Essick3938dc62016-11-01 08:56:56 -0700443 return true;
444}
Ray Essickb5fac8e2016-12-12 11:33:56 -0800445
446bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
447 Prop *prop = findProp(name);
448 if (prop == NULL || prop->mType != kTypeRate) {
Ray Essick3938dc62016-11-01 08:56:56 -0700449 return false;
450 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800451 if (count != NULL) {
452 *count = prop->u.rate.count;
453 }
454 if (duration != NULL) {
455 *duration = prop->u.rate.duration;
456 }
457 if (rate != NULL) {
458 double r = 0.0;
459 if (prop->u.rate.duration != 0) {
460 r = prop->u.rate.count / (double) prop->u.rate.duration;
461 }
462 *rate = r;
463 }
464 return true;
465}
466
467bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
468 Prop *prop = findProp(name);
469 if (prop == NULL || prop->mType != kTypeDouble) {
470 return false;
471 }
472 if (value != NULL) {
473 *value = prop->u.doubleValue;
474 }
Ray Essick3938dc62016-11-01 08:56:56 -0700475 return true;
476}
477
478// caller responsible for the returned string
Ray Essickb5fac8e2016-12-12 11:33:56 -0800479bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
480 Prop *prop = findProp(name);
Ray Essick9db7b812018-11-15 12:42:19 -0800481 if (prop == NULL || prop->mType != kTypeCString) {
Ray Essick3938dc62016-11-01 08:56:56 -0700482 return false;
483 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800484 if (value != NULL) {
485 *value = strdup(prop->u.CStringValue);
486 }
Ray Essick3938dc62016-11-01 08:56:56 -0700487 return true;
488}
489
Ray Essick20147322018-11-17 09:08:39 -0800490bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
491 Prop *prop = findProp(name);
492 if (prop == NULL || prop->mType != kTypeCString) {
493 return false;
494 }
495 if (value != NULL) {
496 // std::string makes a copy for us
497 *value = prop->u.CStringValue;
498 }
499 return true;
500}
501
Ray Essick3938dc62016-11-01 08:56:56 -0700502// remove indicated keys and their values
503// return value is # keys removed
504int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
505 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800506 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700507 return -1;
508 }
509 for (ssize_t i = 0 ; i < n ; i++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800510 const char *name = attrs[i];
511 size_t len = strlen(name);
512 size_t j = findPropIndex(name, len);
513 if (j >= mPropCount) {
514 // not there
515 continue;
516 } else if (j+1 == mPropCount) {
517 // last one, shorten
Ray Essick3938dc62016-11-01 08:56:56 -0700518 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800519 clearProp(&mProps[j]);
520 mPropCount--;
521 } else {
522 // in the middle, bring last one down and shorten
523 zapped++;
524 clearProp(&mProps[j]);
525 mProps[j] = mProps[mPropCount-1];
526 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700527 }
528 }
529 return zapped;
530}
531
532// remove any keys NOT in the provided list
533// return value is # keys removed
534int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
535 int zapped = 0;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800536 if (attrs == NULL || n <= 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700537 return -1;
538 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800539 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
540 Prop *prop = &mProps[i];
541 for (ssize_t j = 0; j < n ; j++) {
542 if (strcmp(prop->mName, attrs[j]) == 0) {
543 clearProp(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700544 zapped++;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800545 if (i != (ssize_t)(mPropCount-1)) {
546 *prop = mProps[mPropCount-1];
547 }
548 initProp(&mProps[mPropCount-1]);
549 mPropCount--;
Ray Essick3938dc62016-11-01 08:56:56 -0700550 break;
551 }
552 }
553 }
554 return zapped;
555}
556
557// remove a single key
558// return value is 0 (not found) or 1 (found and removed)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800559int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
560 return filter(1, &name);
Ray Essick3938dc62016-11-01 08:56:56 -0700561}
562
Ray Essick3938dc62016-11-01 08:56:56 -0700563// handle individual items/properties stored within the class
564//
Ray Essick3938dc62016-11-01 08:56:56 -0700565
Ray Essickb5fac8e2016-12-12 11:33:56 -0800566void MediaAnalyticsItem::initProp(Prop *prop) {
567 if (prop != NULL) {
568 prop->mName = NULL;
569 prop->mNameLen = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700570
Ray Essickb5fac8e2016-12-12 11:33:56 -0800571 prop->mType = kTypeNone;
Ray Essick3938dc62016-11-01 08:56:56 -0700572 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800573}
574
575void MediaAnalyticsItem::clearProp(Prop *prop)
576{
577 if (prop != NULL) {
578 if (prop->mName != NULL) {
579 free((void *)prop->mName);
580 prop->mName = NULL;
581 prop->mNameLen = 0;
582 }
583
584 clearPropValue(prop);
585 }
586}
587
588void MediaAnalyticsItem::clearPropValue(Prop *prop)
589{
590 if (prop != NULL) {
591 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
592 free(prop->u.CStringValue);
593 prop->u.CStringValue = NULL;
594 }
595 prop->mType = kTypeNone;
596 }
597}
598
599void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
600{
601 // get rid of any pointers in the dst
602 clearProp(dst);
603
604 *dst = *src;
605
606 // fix any pointers that we blindly copied, so we have our own copies
607 if (dst->mName) {
608 void *p = malloc(dst->mNameLen + 1);
Ray Essick9ce18f72018-05-07 15:54:30 -0700609 LOG_ALWAYS_FATAL_IF(p == NULL,
610 "failed malloc() duping property '%s' (len %zu)",
611 dst->mName, dst->mNameLen);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800612 memcpy (p, src->mName, dst->mNameLen + 1);
613 dst->mName = (const char *) p;
614 }
615 if (dst->mType == kTypeCString) {
616 dst->u.CStringValue = strdup(src->u.CStringValue);
617 }
618}
619
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700620bool MediaAnalyticsItem::growProps(int increment)
Ray Essickb5fac8e2016-12-12 11:33:56 -0800621{
622 if (increment <= 0) {
623 increment = kGrowProps;
624 }
625 int nsize = mPropSize + increment;
626 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
627
628 if (ni != NULL) {
629 for (int i = mPropSize; i < nsize; i++) {
630 initProp(&ni[i]);
631 }
632 mProps = ni;
633 mPropSize = nsize;
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700634 return true;
635 } else {
636 ALOGW("MediaAnalyticsItem::growProps fails");
637 return false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800638 }
Ray Essick3938dc62016-11-01 08:56:56 -0700639}
640
641// Parcel / serialize things for binder calls
642//
643
644int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
645 // into 'this' object
646 // .. we make a copy of the string to put away.
647 mKey = data.readCString();
Ray Essickf65f4212017-08-31 11:41:19 -0700648 mPid = data.readInt32();
649 mUid = data.readInt32();
650 mPkgName = data.readCString();
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800651 mPkgVersionCode = data.readInt64();
Ray Essick3938dc62016-11-01 08:56:56 -0700652 mSessionID = data.readInt64();
Ray Essick92d23b42018-01-29 12:10:30 -0800653 // We no longer pay attention to user setting of finalized, BUT it's
654 // still part of the wire packet -- so read & discard.
Ray Essick3938dc62016-11-01 08:56:56 -0700655 mFinalized = data.readInt32();
Ray Essick92d23b42018-01-29 12:10:30 -0800656 mFinalized = 1;
Ray Essick3938dc62016-11-01 08:56:56 -0700657 mTimestamp = data.readInt64();
658
659 int count = data.readInt32();
660 for (int i = 0; i < count ; i++) {
661 MediaAnalyticsItem::Attr attr = data.readCString();
662 int32_t ztype = data.readInt32();
663 switch (ztype) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800664 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700665 setInt32(attr, data.readInt32());
666 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800667 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700668 setInt64(attr, data.readInt64());
669 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800670 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700671 setDouble(attr, data.readDouble());
672 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800673 case MediaAnalyticsItem::kTypeCString:
Ray Essick3938dc62016-11-01 08:56:56 -0700674 setCString(attr, data.readCString());
675 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800676 case MediaAnalyticsItem::kTypeRate:
677 {
678 int64_t count = data.readInt64();
679 int64_t duration = data.readInt64();
680 setRate(attr, count, duration);
681 }
682 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700683 default:
684 ALOGE("reading bad item type: %d, idx %d",
685 ztype, i);
686 return -1;
687 }
688 }
689
690 return 0;
691}
692
693int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
694 if (data == NULL) return -1;
695
696
697 data->writeCString(mKey.c_str());
Ray Essickf65f4212017-08-31 11:41:19 -0700698 data->writeInt32(mPid);
699 data->writeInt32(mUid);
700 data->writeCString(mPkgName.c_str());
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800701 data->writeInt64(mPkgVersionCode);
Ray Essick3938dc62016-11-01 08:56:56 -0700702 data->writeInt64(mSessionID);
703 data->writeInt32(mFinalized);
704 data->writeInt64(mTimestamp);
705
706 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800707 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700708 data->writeInt32(count);
709 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800710 Prop *prop = &mProps[i];
711 data->writeCString(prop->mName);
712 data->writeInt32(prop->mType);
713 switch (prop->mType) {
714 case MediaAnalyticsItem::kTypeInt32:
715 data->writeInt32(prop->u.int32Value);
716 break;
717 case MediaAnalyticsItem::kTypeInt64:
718 data->writeInt64(prop->u.int64Value);
719 break;
720 case MediaAnalyticsItem::kTypeDouble:
721 data->writeDouble(prop->u.doubleValue);
722 break;
723 case MediaAnalyticsItem::kTypeRate:
724 data->writeInt64(prop->u.rate.count);
725 data->writeInt64(prop->u.rate.duration);
726 break;
727 case MediaAnalyticsItem::kTypeCString:
728 data->writeCString(prop->u.CStringValue);
729 break;
730 default:
731 ALOGE("found bad Prop type: %d, idx %d, name %s",
732 prop->mType, i, prop->mName);
733 break;
Ray Essick3938dc62016-11-01 08:56:56 -0700734 }
735 }
736
737 return 0;
738}
739
740
Ray Essick20147322018-11-17 09:08:39 -0800741const char *MediaAnalyticsItem::toCString() {
742 return toCString(PROTO_LAST);
743}
744
745const char * MediaAnalyticsItem::toCString(int version) {
746 std::string val = toString(version);
747 return strdup(val.c_str());
748}
749
Ray Essick783bd0d2018-01-11 11:10:35 -0800750std::string MediaAnalyticsItem::toString() {
Ray Essick5b77bd22018-01-23 16:11:06 -0800751 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700752}
Ray Essick3938dc62016-11-01 08:56:56 -0700753
Ray Essick783bd0d2018-01-11 11:10:35 -0800754std::string MediaAnalyticsItem::toString(int version) {
Ray Essickf65f4212017-08-31 11:41:19 -0700755
756 // v0 : released with 'o'
757 // v1 : bug fix (missing pid/finalized separator),
758 // adds apk name, apk version code
759
760 if (version <= PROTO_FIRST) {
761 // default to original v0 format, until proper parsers are in place
762 version = PROTO_V0;
763 } else if (version > PROTO_LAST) {
764 version = PROTO_LAST;
765 }
766
Ray Essick783bd0d2018-01-11 11:10:35 -0800767 std::string result;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800768 char buffer[512];
Ray Essick3938dc62016-11-01 08:56:56 -0700769
Ray Essickf65f4212017-08-31 11:41:19 -0700770 if (version == PROTO_V0) {
771 result = "(";
772 } else {
773 snprintf(buffer, sizeof(buffer), "[%d:", version);
774 result.append(buffer);
775 }
776
Ray Essick3938dc62016-11-01 08:56:56 -0700777 // same order as we spill into the parcel, although not required
778 // key+session are our primary matching criteria
779 result.append(mKey.c_str());
780 result.append(":");
781 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
782 result.append(buffer);
783
Ray Essickf65f4212017-08-31 11:41:19 -0700784 snprintf(buffer, sizeof(buffer), "%d:", mUid);
785 result.append(buffer);
786
787 if (version >= PROTO_V1) {
788 result.append(mPkgName);
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800789 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700790 result.append(buffer);
791 }
792
793 // in 'o' (v1) , the separator between pid and finalized was omitted
794 if (version <= PROTO_V0) {
795 snprintf(buffer, sizeof(buffer), "%d", mPid);
796 } else {
797 snprintf(buffer, sizeof(buffer), "%d:", mPid);
798 }
Ray Essick3938dc62016-11-01 08:56:56 -0700799 result.append(buffer);
800
801 snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
802 result.append(buffer);
803 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
804 result.append(buffer);
805
806 // set of items
Ray Essickb5fac8e2016-12-12 11:33:56 -0800807 int count = mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -0700808 snprintf(buffer, sizeof(buffer), "%d:", count);
809 result.append(buffer);
810 for (int i = 0 ; i < count; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800811 Prop *prop = &mProps[i];
812 switch (prop->mType) {
813 case MediaAnalyticsItem::kTypeInt32:
Ray Essick3938dc62016-11-01 08:56:56 -0700814 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800815 "%s=%d:", prop->mName, prop->u.int32Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700816 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800817 case MediaAnalyticsItem::kTypeInt64:
Ray Essick3938dc62016-11-01 08:56:56 -0700818 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800819 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
Ray Essick3938dc62016-11-01 08:56:56 -0700820 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800821 case MediaAnalyticsItem::kTypeDouble:
Ray Essick3938dc62016-11-01 08:56:56 -0700822 snprintf(buffer,sizeof(buffer),
Ray Essickb5fac8e2016-12-12 11:33:56 -0800823 "%s=%e:", prop->mName, prop->u.doubleValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700824 break;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800825 case MediaAnalyticsItem::kTypeRate:
826 snprintf(buffer,sizeof(buffer),
827 "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
828 prop->u.rate.count, prop->u.rate.duration);
829 break;
830 case MediaAnalyticsItem::kTypeCString:
831 snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700832 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800833 // XXX: sanitize string for ':' '='
834 result.append(prop->u.CStringValue);
Ray Essick3938dc62016-11-01 08:56:56 -0700835 buffer[0] = ':';
836 buffer[1] = '\0';
837 break;
838 default:
Ray Essickb5fac8e2016-12-12 11:33:56 -0800839 ALOGE("to_String bad item type: %d for %s",
840 prop->mType, prop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -0700841 break;
842 }
843 result.append(buffer);
844 }
845
Ray Essickf65f4212017-08-31 11:41:19 -0700846 if (version == PROTO_V0) {
847 result.append(")");
848 } else {
849 result.append("]");
850 }
Ray Essick3938dc62016-11-01 08:56:56 -0700851
852 return result;
853}
854
855// for the lazy, we offer methods that finds the service and
856// calls the appropriate daemon
857bool MediaAnalyticsItem::selfrecord() {
858 return selfrecord(false);
859}
860
861bool MediaAnalyticsItem::selfrecord(bool forcenew) {
862
Ray Essickb5fac8e2016-12-12 11:33:56 -0800863 if (DEBUG_API) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800864 std::string p = this->toString();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800865 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
866 }
Ray Essick3938dc62016-11-01 08:56:56 -0700867
868 sp<IMediaAnalyticsService> svc = getInstance();
869
870 if (svc != NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700871 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
872 if (newid == SessionIDInvalid) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800873 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700874 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
875 return false;
876 }
Ray Essick3938dc62016-11-01 08:56:56 -0700877 return true;
878 } else {
Ray Essick783bd0d2018-01-11 11:10:35 -0800879 std::string p = this->toString();
Ray Essick2ab3c432017-10-02 09:29:49 -0700880 ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700881 return false;
882 }
883}
884
885// get a connection we can reuse for most of our lifetime
886// static
887sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
888static Mutex sInitMutex;
Ray Essick2ab3c432017-10-02 09:29:49 -0700889static int remainingBindAttempts = SVC_TRIES;
Ray Essick3938dc62016-11-01 08:56:56 -0700890
891//static
892bool MediaAnalyticsItem::isEnabled() {
893 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
894
895 if (enabled == -1) {
896 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
897 }
898 if (enabled == -1) {
899 enabled = MediaAnalyticsItem::EnabledProperty_default;
900 }
901 if (enabled <= 0) {
902 return false;
903 }
904 return true;
905}
906
Ray Essick2ab3c432017-10-02 09:29:49 -0700907
908// monitor health of our connection to the metrics service
909class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
910 virtual void binderDied(const wp<IBinder> &) {
911 ALOGW("Reacquire service connection on next request");
912 MediaAnalyticsItem::dropInstance();
913 }
914};
915
916static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
917
918// static
919void MediaAnalyticsItem::dropInstance() {
920 Mutex::Autolock _l(sInitMutex);
921 remainingBindAttempts = SVC_TRIES;
922 sAnalyticsService = NULL;
923}
924
Ray Essick3938dc62016-11-01 08:56:56 -0700925//static
926sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
Ray Essick2ab3c432017-10-02 09:29:49 -0700927
Ray Essickd38e1742017-01-23 15:17:06 -0800928 static const char *servicename = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -0700929 int enabled = isEnabled();
930
931 if (enabled == false) {
932 if (DEBUG_SERVICEACCESS) {
933 ALOGD("disabled");
934 }
935 return NULL;
936 }
937
Ray Essick79a89ef2017-04-24 15:52:54 -0700938 // completely skip logging from certain UIDs. We do this here
939 // to avoid the multi-second timeouts while we learn that
940 // sepolicy will not let us find the service.
941 // We do this only for a select set of UIDs
942 // The sepolicy protection is still in place, we just want a faster
943 // response from this specific, small set of uids.
944 {
945 uid_t uid = getuid();
946 switch (uid) {
947 case AID_RADIO: // telephony subsystem, RIL
948 return NULL;
949 break;
950 default:
951 // let sepolicy deny access if appropriate
952 break;
953 }
954 }
955
Ray Essick3938dc62016-11-01 08:56:56 -0700956 {
957 Mutex::Autolock _l(sInitMutex);
958 const char *badness = "";
959
Ray Essick2ab3c432017-10-02 09:29:49 -0700960 // think of remainingBindAttempts as telling us whether service==NULL because
Ray Essickb5fac8e2016-12-12 11:33:56 -0800961 // (1) we haven't tried to initialize it yet
962 // (2) we've tried to initialize it, but failed.
Ray Essick2ab3c432017-10-02 09:29:49 -0700963 if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700964 sp<IServiceManager> sm = defaultServiceManager();
965 if (sm != NULL) {
966 sp<IBinder> binder = sm->getService(String16(servicename));
967 if (binder != NULL) {
968 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
Ray Essick2ab3c432017-10-02 09:29:49 -0700969 if (sNotifier != NULL) {
970 sNotifier = NULL;
971 }
972 sNotifier = new MediaMetricsDeathNotifier();
973 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700974 } else {
975 badness = "did not find service";
976 }
977 } else {
978 badness = "No Service Manager access";
979 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800980
981 if (sAnalyticsService == NULL) {
Ray Essick2ab3c432017-10-02 09:29:49 -0700982 if (remainingBindAttempts > 0) {
983 remainingBindAttempts--;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800984 }
985 if (DEBUG_SERVICEACCESS) {
Ray Essick3938dc62016-11-01 08:56:56 -0700986 ALOGD("Unable to bind to service %s: %s", servicename, badness);
987 }
988 }
989 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800990
Ray Essick3938dc62016-11-01 08:56:56 -0700991 return sAnalyticsService;
992 }
993}
994
Ray Essick3938dc62016-11-01 08:56:56 -0700995// merge the info from 'incoming' into this record.
996// we finish with a union of this+incoming and special handling for collisions
Ray Essickb5fac8e2016-12-12 11:33:56 -0800997bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
Ray Essick3938dc62016-11-01 08:56:56 -0700998
999 // if I don't have key or session id, take them from incoming
1000 // 'this' should never be missing both of them...
1001 if (mKey.empty()) {
1002 mKey = incoming->mKey;
1003 } else if (mSessionID == 0) {
1004 mSessionID = incoming->mSessionID;
1005 }
1006
Ray Essick3938dc62016-11-01 08:56:56 -07001007 // for each attribute from 'incoming', resolve appropriately
Ray Essickb5fac8e2016-12-12 11:33:56 -08001008 int nattr = incoming->mPropCount;
Ray Essick3938dc62016-11-01 08:56:56 -07001009 for (int i = 0 ; i < nattr; i++ ) {
Ray Essickb5fac8e2016-12-12 11:33:56 -08001010 Prop *iprop = &incoming->mProps[i];
Ray Essickb5fac8e2016-12-12 11:33:56 -08001011 const char *p = iprop->mName;
1012 size_t len = strlen(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001013
1014 // should ignore a zero length name...
1015 if (len == 0) {
1016 continue;
1017 }
1018
1019 Prop *oprop = findProp(iprop->mName);
Ray Essick3938dc62016-11-01 08:56:56 -07001020
Ray Essickb5fac8e2016-12-12 11:33:56 -08001021 if (oprop == NULL) {
1022 // no oprop, so we insert the new one
1023 oprop = allocateProp(p);
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001024 if (oprop != NULL) {
1025 copyProp(oprop, iprop);
1026 } else {
1027 ALOGW("dropped property '%s'", iprop->mName);
Ray Essickb5fac8e2016-12-12 11:33:56 -08001028 }
Ray Essick9bb7e3b2017-10-23 13:01:48 -07001029 } else {
1030 copyProp(oprop, iprop);
Ray Essick3938dc62016-11-01 08:56:56 -07001031 }
1032 }
1033
1034 // not sure when we'd return false...
1035 return true;
1036}
1037
1038} // namespace android
1039