1 /*
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 
20 #include <inttypes.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 
25 #include <binder/Parcel.h>
26 #include <utils/Errors.h>
27 #include <utils/Log.h>
28 #include <utils/Mutex.h>
29 #include <utils/SortedVector.h>
30 #include <utils/threads.h>
31 
32 #include <binder/IServiceManager.h>
33 #include <media/IMediaAnalyticsService.h>
34 #include <media/MediaAnalyticsItem.h>
35 #include <private/android_filesystem_config.h>
36 
37 namespace android {
38 
39 #define DEBUG_SERVICEACCESS     0
40 #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
46 
47 // the few universal keys we have
48 const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny  = "any";
49 const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone  = "none";
50 
51 const char * const MediaAnalyticsItem::EnabledProperty  = "media.metrics.enabled";
52 const char * const MediaAnalyticsItem::EnabledPropertyPersist  = "persist.media.metrics.enabled";
53 const int MediaAnalyticsItem::EnabledProperty_default  = 1;
54 
55 
56 // access functions for the class
MediaAnalyticsItem()57 MediaAnalyticsItem::MediaAnalyticsItem()
58     : mPid(-1),
59       mUid(-1),
60       mPkgVersionCode(0),
61       mSessionID(MediaAnalyticsItem::SessionIDNone),
62       mTimestamp(0),
63       mFinalized(1),
64       mPropCount(0), mPropSize(0), mProps(NULL)
65 {
66     mKey = MediaAnalyticsItem::kKeyNone;
67 }
68 
MediaAnalyticsItem(MediaAnalyticsItem::Key key)69 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
70     : mPid(-1),
71       mUid(-1),
72       mPkgVersionCode(0),
73       mSessionID(MediaAnalyticsItem::SessionIDNone),
74       mTimestamp(0),
75       mFinalized(1),
76       mPropCount(0), mPropSize(0), mProps(NULL)
77 {
78     if (DEBUG_ALLOCATIONS) {
79         ALOGD("Allocate MediaAnalyticsItem @ %p", this);
80     }
81     mKey = key;
82 }
83 
~MediaAnalyticsItem()84 MediaAnalyticsItem::~MediaAnalyticsItem() {
85     if (DEBUG_ALLOCATIONS) {
86         ALOGD("Destroy  MediaAnalyticsItem @ %p", this);
87     }
88     clear();
89 }
90 
clear()91 void MediaAnalyticsItem::clear() {
92 
93     // clean allocated storage from key
94     mKey.clear();
95 
96     // clean various major parameters
97     mSessionID = MediaAnalyticsItem::SessionIDNone;
98 
99     // clean attributes
100     // contents of the attributes
101     for (size_t i = 0 ; i < mPropCount; i++ ) {
102         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
dup()116 MediaAnalyticsItem *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;
123         dst->mPkgName = this->mPkgName;
124         dst->mPkgVersionCode = this->mPkgVersionCode;
125         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 
setSessionID(MediaAnalyticsItem::SessionID_t id)140 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
141     mSessionID = id;
142     return *this;
143 }
144 
getSessionID() const145 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
146     return mSessionID;
147 }
148 
generateSessionID()149 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
150 
151     if (mSessionID == SessionIDNone) {
152         // get one from the server
153         MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
154         sp<IMediaAnalyticsService> svc = getInstance();
155         if (svc != NULL) {
156             newid = svc->generateUniqueSessionID();
157         }
158         mSessionID = newid;
159     }
160 
161     return mSessionID;
162 }
163 
clearSessionID()164 MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
165     mSessionID = MediaAnalyticsItem::SessionIDNone;
166     return *this;
167 }
168 
setTimestamp(nsecs_t ts)169 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
170     mTimestamp = ts;
171     return *this;
172 }
173 
getTimestamp() const174 nsecs_t MediaAnalyticsItem::getTimestamp() const {
175     return mTimestamp;
176 }
177 
setPid(pid_t pid)178 MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
179     mPid = pid;
180     return *this;
181 }
182 
getPid() const183 pid_t MediaAnalyticsItem::getPid() const {
184     return mPid;
185 }
186 
setUid(uid_t uid)187 MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
188     mUid = uid;
189     return *this;
190 }
191 
getUid() const192 uid_t MediaAnalyticsItem::getUid() const {
193     return mUid;
194 }
195 
setPkgName(const std::string & pkgName)196 MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
197     mPkgName = pkgName;
198     return *this;
199 }
200 
setPkgVersionCode(int64_t pkgVersionCode)201 MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
202     mPkgVersionCode = pkgVersionCode;
203     return *this;
204 }
205 
getPkgVersionCode() const206 int64_t MediaAnalyticsItem::getPkgVersionCode() const {
207     return mPkgVersionCode;
208 }
209 
210 // this key is for the overall record -- "codec", "player", "drm", etc
setKey(MediaAnalyticsItem::Key key)211 MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
212     mKey = key;
213     return *this;
214 }
215 
getKey()216 MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
217     return mKey;
218 }
219 
220 // number of attributes we have in this record
count() const221 int32_t MediaAnalyticsItem::count() const {
222     return mPropCount;
223 }
224 
225 // find the proper entry in the list
findPropIndex(const char * name,size_t len)226 size_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 
findProp(const char * name)241 MediaAnalyticsItem::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 
setName(const char * name,size_t len)250 void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
251     free((void *)mName);
252     mName = (const char *) malloc(len+1);
253     LOG_ALWAYS_FATAL_IF(mName == NULL,
254                         "failed malloc() for property '%s' (len %zu)",
255                         name, len);
256     memcpy ((void *)mName, name, len+1);
257     mNameLen = len;
258 }
259 
260 // consider this "find-or-allocate".
261 // caller validates type and uses clearPropValue() accordingly
allocateProp(const char * name)262 MediaAnalyticsItem::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) {
271             if (growProps() == false) {
272                 ALOGE("failed allocation for new props");
273                 return NULL;
274             }
275         }
276         i = mPropCount++;
277         prop = &mProps[i];
278         prop->setName(name, len);
279     }
280 
281     return prop;
282 }
283 
284 // used within the summarizers; return whether property existed
removeProp(const char * name)285 bool 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
293             copyProp(prop, &mProps[mPropCount-1]);
294             clearProp(&mProps[mPropCount-1]);
295         }
296         mPropCount--;
297         return true;
298     }
299     return false;
300 }
301 
302 // set the values
setInt32(MediaAnalyticsItem::Attr name,int32_t value)303 void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
304     Prop *prop = allocateProp(name);
305     if (prop != NULL) {
306         clearPropValue(prop);
307         prop->mType = kTypeInt32;
308         prop->u.int32Value = value;
309     }
310 }
311 
setInt64(MediaAnalyticsItem::Attr name,int64_t value)312 void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
313     Prop *prop = allocateProp(name);
314     if (prop != NULL) {
315         clearPropValue(prop);
316         prop->mType = kTypeInt64;
317         prop->u.int64Value = value;
318     }
319 }
320 
setDouble(MediaAnalyticsItem::Attr name,double value)321 void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
322     Prop *prop = allocateProp(name);
323     if (prop != NULL) {
324         clearPropValue(prop);
325         prop->mType = kTypeDouble;
326         prop->u.doubleValue = value;
327     }
328 }
329 
setCString(MediaAnalyticsItem::Attr name,const char * value)330 void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
331 
332     Prop *prop = allocateProp(name);
333     // any old value will be gone
334     if (prop != NULL) {
335         clearPropValue(prop);
336         prop->mType = kTypeCString;
337         prop->u.CStringValue = strdup(value);
338     }
339 }
340 
setRate(MediaAnalyticsItem::Attr name,int64_t count,int64_t duration)341 void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
342     Prop *prop = allocateProp(name);
343     if (prop != NULL) {
344         clearPropValue(prop);
345         prop->mType = kTypeRate;
346         prop->u.rate.count = count;
347         prop->u.rate.duration = duration;
348     }
349 }
350 
351 
352 // find/add/set fused into a single operation
addInt32(MediaAnalyticsItem::Attr name,int32_t value)353 void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
354     Prop *prop = allocateProp(name);
355     if (prop == NULL) {
356         return;
357     }
358     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;
367     }
368 }
369 
addInt64(MediaAnalyticsItem::Attr name,int64_t value)370 void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
371     Prop *prop = allocateProp(name);
372     if (prop == NULL) {
373         return;
374     }
375     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;
384     }
385 }
386 
addRate(MediaAnalyticsItem::Attr name,int64_t count,int64_t duration)387 void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
388     Prop *prop = allocateProp(name);
389     if (prop == NULL) {
390         return;
391     }
392     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;
403     }
404 }
405 
addDouble(MediaAnalyticsItem::Attr name,double value)406 void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
407     Prop *prop = allocateProp(name);
408     if (prop == NULL) {
409         return;
410     }
411     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;
420     }
421 }
422 
423 // find & extract values
getInt32(MediaAnalyticsItem::Attr name,int32_t * value)424 bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
425     Prop *prop = findProp(name);
426     if (prop == NULL || prop->mType != kTypeInt32) {
427         return false;
428     }
429     if (value != NULL) {
430         *value = prop->u.int32Value;
431     }
432     return true;
433 }
434 
getInt64(MediaAnalyticsItem::Attr name,int64_t * value)435 bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
436     Prop *prop = findProp(name);
437     if (prop == NULL || prop->mType != kTypeInt64) {
438         return false;
439     }
440     if (value != NULL) {
441         *value = prop->u.int64Value;
442     }
443     return true;
444 }
445 
getRate(MediaAnalyticsItem::Attr name,int64_t * count,int64_t * duration,double * rate)446 bool 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) {
449         return false;
450     }
451     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 
getDouble(MediaAnalyticsItem::Attr name,double * value)467 bool 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     }
475     return true;
476 }
477 
478 // caller responsible for the returned string
getCString(MediaAnalyticsItem::Attr name,char ** value)479 bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
480     Prop *prop = findProp(name);
481     if (prop == NULL || prop->mType != kTypeDouble) {
482         return false;
483     }
484     if (value != NULL) {
485         *value = strdup(prop->u.CStringValue);
486     }
487     return true;
488 }
489 
490 // remove indicated keys and their values
491 // return value is # keys removed
filter(int n,MediaAnalyticsItem::Attr attrs[])492 int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
493     int zapped = 0;
494     if (attrs == NULL || n <= 0) {
495         return -1;
496     }
497     for (ssize_t i = 0 ; i < n ;  i++) {
498         const char *name = attrs[i];
499         size_t len = strlen(name);
500         size_t j = findPropIndex(name, len);
501         if (j >= mPropCount) {
502             // not there
503             continue;
504         } else if (j+1 == mPropCount) {
505             // last one, shorten
506             zapped++;
507             clearProp(&mProps[j]);
508             mPropCount--;
509         } else {
510             // in the middle, bring last one down and shorten
511             zapped++;
512             clearProp(&mProps[j]);
513             mProps[j] = mProps[mPropCount-1];
514             mPropCount--;
515         }
516     }
517     return zapped;
518 }
519 
520 // remove any keys NOT in the provided list
521 // return value is # keys removed
filterNot(int n,MediaAnalyticsItem::Attr attrs[])522 int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
523     int zapped = 0;
524     if (attrs == NULL || n <= 0) {
525         return -1;
526     }
527     for (ssize_t i = mPropCount-1 ; i >=0 ;  i--) {
528         Prop *prop = &mProps[i];
529         for (ssize_t j = 0; j < n ; j++) {
530             if (strcmp(prop->mName, attrs[j]) == 0) {
531                 clearProp(prop);
532                 zapped++;
533                 if (i != (ssize_t)(mPropCount-1)) {
534                     *prop = mProps[mPropCount-1];
535                 }
536                 initProp(&mProps[mPropCount-1]);
537                 mPropCount--;
538                 break;
539             }
540         }
541     }
542     return zapped;
543 }
544 
545 // remove a single key
546 // return value is 0 (not found) or 1 (found and removed)
filter(MediaAnalyticsItem::Attr name)547 int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
548     return filter(1, &name);
549 }
550 
551 // handle individual items/properties stored within the class
552 //
553 
initProp(Prop * prop)554 void MediaAnalyticsItem::initProp(Prop *prop) {
555     if (prop != NULL) {
556         prop->mName = NULL;
557         prop->mNameLen = 0;
558 
559         prop->mType = kTypeNone;
560     }
561 }
562 
clearProp(Prop * prop)563 void MediaAnalyticsItem::clearProp(Prop *prop)
564 {
565     if (prop != NULL) {
566         if (prop->mName != NULL) {
567             free((void *)prop->mName);
568             prop->mName = NULL;
569             prop->mNameLen = 0;
570         }
571 
572         clearPropValue(prop);
573     }
574 }
575 
clearPropValue(Prop * prop)576 void MediaAnalyticsItem::clearPropValue(Prop *prop)
577 {
578     if (prop != NULL) {
579         if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
580             free(prop->u.CStringValue);
581             prop->u.CStringValue = NULL;
582         }
583         prop->mType = kTypeNone;
584     }
585 }
586 
copyProp(Prop * dst,const Prop * src)587 void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
588 {
589     // get rid of any pointers in the dst
590     clearProp(dst);
591 
592     *dst = *src;
593 
594     // fix any pointers that we blindly copied, so we have our own copies
595     if (dst->mName) {
596         void *p =  malloc(dst->mNameLen + 1);
597         LOG_ALWAYS_FATAL_IF(p == NULL,
598                             "failed malloc() duping property '%s' (len %zu)",
599                             dst->mName, dst->mNameLen);
600         memcpy (p, src->mName, dst->mNameLen + 1);
601         dst->mName = (const char *) p;
602     }
603     if (dst->mType == kTypeCString) {
604         dst->u.CStringValue = strdup(src->u.CStringValue);
605     }
606 }
607 
growProps(int increment)608 bool MediaAnalyticsItem::growProps(int increment)
609 {
610     if (increment <= 0) {
611         increment = kGrowProps;
612     }
613     int nsize = mPropSize + increment;
614     Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
615 
616     if (ni != NULL) {
617         for (int i = mPropSize; i < nsize; i++) {
618             initProp(&ni[i]);
619         }
620         mProps = ni;
621         mPropSize = nsize;
622         return true;
623     } else {
624         ALOGW("MediaAnalyticsItem::growProps fails");
625         return false;
626     }
627 }
628 
629 // Parcel / serialize things for binder calls
630 //
631 
readFromParcel(const Parcel & data)632 int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
633     // into 'this' object
634     // .. we make a copy of the string to put away.
635     mKey = data.readCString();
636     mPid = data.readInt32();
637     mUid = data.readInt32();
638     mPkgName = data.readCString();
639     mPkgVersionCode = data.readInt64();
640     mSessionID = data.readInt64();
641     // We no longer pay attention to user setting of finalized, BUT it's
642     // still part of the wire packet -- so read & discard.
643     mFinalized = data.readInt32();
644     mFinalized = 1;
645     mTimestamp = data.readInt64();
646 
647     int count = data.readInt32();
648     for (int i = 0; i < count ; i++) {
649             MediaAnalyticsItem::Attr attr = data.readCString();
650             int32_t ztype = data.readInt32();
651                 switch (ztype) {
652                     case MediaAnalyticsItem::kTypeInt32:
653                             setInt32(attr, data.readInt32());
654                             break;
655                     case MediaAnalyticsItem::kTypeInt64:
656                             setInt64(attr, data.readInt64());
657                             break;
658                     case MediaAnalyticsItem::kTypeDouble:
659                             setDouble(attr, data.readDouble());
660                             break;
661                     case MediaAnalyticsItem::kTypeCString:
662                             setCString(attr, data.readCString());
663                             break;
664                     case MediaAnalyticsItem::kTypeRate:
665                             {
666                                 int64_t count = data.readInt64();
667                                 int64_t duration = data.readInt64();
668                                 setRate(attr, count, duration);
669                             }
670                             break;
671                     default:
672                             ALOGE("reading bad item type: %d, idx %d",
673                                   ztype, i);
674                             return -1;
675                 }
676     }
677 
678     return 0;
679 }
680 
writeToParcel(Parcel * data)681 int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
682     if (data == NULL) return -1;
683 
684 
685     data->writeCString(mKey.c_str());
686     data->writeInt32(mPid);
687     data->writeInt32(mUid);
688     data->writeCString(mPkgName.c_str());
689     data->writeInt64(mPkgVersionCode);
690     data->writeInt64(mSessionID);
691     data->writeInt32(mFinalized);
692     data->writeInt64(mTimestamp);
693 
694     // set of items
695     int count = mPropCount;
696     data->writeInt32(count);
697     for (int i = 0 ; i < count; i++ ) {
698             Prop *prop = &mProps[i];
699             data->writeCString(prop->mName);
700             data->writeInt32(prop->mType);
701             switch (prop->mType) {
702                 case MediaAnalyticsItem::kTypeInt32:
703                         data->writeInt32(prop->u.int32Value);
704                         break;
705                 case MediaAnalyticsItem::kTypeInt64:
706                         data->writeInt64(prop->u.int64Value);
707                         break;
708                 case MediaAnalyticsItem::kTypeDouble:
709                         data->writeDouble(prop->u.doubleValue);
710                         break;
711                 case MediaAnalyticsItem::kTypeRate:
712                         data->writeInt64(prop->u.rate.count);
713                         data->writeInt64(prop->u.rate.duration);
714                         break;
715                 case MediaAnalyticsItem::kTypeCString:
716                         data->writeCString(prop->u.CStringValue);
717                         break;
718                 default:
719                         ALOGE("found bad Prop type: %d, idx %d, name %s",
720                               prop->mType, i, prop->mName);
721                         break;
722             }
723     }
724 
725     return 0;
726 }
727 
728 
toString()729 std::string MediaAnalyticsItem::toString() {
730    return toString(PROTO_LAST);
731 }
732 
toString(int version)733 std::string MediaAnalyticsItem::toString(int version) {
734 
735     // v0 : released with 'o'
736     // v1 : bug fix (missing pid/finalized separator),
737     //      adds apk name, apk version code
738 
739     if (version <= PROTO_FIRST) {
740         // default to original v0 format, until proper parsers are in place
741         version = PROTO_V0;
742     } else if (version > PROTO_LAST) {
743         version = PROTO_LAST;
744     }
745 
746     std::string result;
747     char buffer[512];
748 
749     if (version == PROTO_V0) {
750         result = "(";
751     } else {
752         snprintf(buffer, sizeof(buffer), "[%d:", version);
753         result.append(buffer);
754     }
755 
756     // same order as we spill into the parcel, although not required
757     // key+session are our primary matching criteria
758     result.append(mKey.c_str());
759     result.append(":");
760     snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
761     result.append(buffer);
762 
763     snprintf(buffer, sizeof(buffer), "%d:", mUid);
764     result.append(buffer);
765 
766     if (version >= PROTO_V1) {
767         result.append(mPkgName);
768         snprintf(buffer, sizeof(buffer), ":%"  PRId64 ":", mPkgVersionCode);
769         result.append(buffer);
770     }
771 
772     // in 'o' (v1) , the separator between pid and finalized was omitted
773     if (version <= PROTO_V0) {
774         snprintf(buffer, sizeof(buffer), "%d", mPid);
775     } else {
776         snprintf(buffer, sizeof(buffer), "%d:", mPid);
777     }
778     result.append(buffer);
779 
780     snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
781     result.append(buffer);
782     snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
783     result.append(buffer);
784 
785     // set of items
786     int count = mPropCount;
787     snprintf(buffer, sizeof(buffer), "%d:", count);
788     result.append(buffer);
789     for (int i = 0 ; i < count; i++ ) {
790             Prop *prop = &mProps[i];
791             switch (prop->mType) {
792                 case MediaAnalyticsItem::kTypeInt32:
793                         snprintf(buffer,sizeof(buffer),
794                         "%s=%d:", prop->mName, prop->u.int32Value);
795                         break;
796                 case MediaAnalyticsItem::kTypeInt64:
797                         snprintf(buffer,sizeof(buffer),
798                         "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
799                         break;
800                 case MediaAnalyticsItem::kTypeDouble:
801                         snprintf(buffer,sizeof(buffer),
802                         "%s=%e:", prop->mName, prop->u.doubleValue);
803                         break;
804                 case MediaAnalyticsItem::kTypeRate:
805                         snprintf(buffer,sizeof(buffer),
806                         "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
807                         prop->u.rate.count, prop->u.rate.duration);
808                         break;
809                 case MediaAnalyticsItem::kTypeCString:
810                         snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
811                         result.append(buffer);
812                         // XXX: sanitize string for ':' '='
813                         result.append(prop->u.CStringValue);
814                         buffer[0] = ':';
815                         buffer[1] = '\0';
816                         break;
817                 default:
818                         ALOGE("to_String bad item type: %d for %s",
819                               prop->mType, prop->mName);
820                         break;
821             }
822             result.append(buffer);
823     }
824 
825     if (version == PROTO_V0) {
826         result.append(")");
827     } else {
828         result.append("]");
829     }
830 
831     return result;
832 }
833 
834 // for the lazy, we offer methods that finds the service and
835 // calls the appropriate daemon
selfrecord()836 bool MediaAnalyticsItem::selfrecord() {
837     return selfrecord(false);
838 }
839 
selfrecord(bool forcenew)840 bool MediaAnalyticsItem::selfrecord(bool forcenew) {
841 
842     if (DEBUG_API) {
843         std::string p = this->toString();
844         ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
845     }
846 
847     sp<IMediaAnalyticsService> svc = getInstance();
848 
849     if (svc != NULL) {
850         MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
851         if (newid == SessionIDInvalid) {
852             std::string p = this->toString();
853             ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
854             return false;
855         }
856         return true;
857     } else {
858         std::string p = this->toString();
859         ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
860         return false;
861     }
862 }
863 
864 // get a connection we can reuse for most of our lifetime
865 // static
866 sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
867 static Mutex sInitMutex;
868 static int remainingBindAttempts = SVC_TRIES;
869 
870 //static
isEnabled()871 bool MediaAnalyticsItem::isEnabled() {
872     int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
873 
874     if (enabled == -1) {
875         enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
876     }
877     if (enabled == -1) {
878         enabled = MediaAnalyticsItem::EnabledProperty_default;
879     }
880     if (enabled <= 0) {
881         return false;
882     }
883     return true;
884 }
885 
886 
887 // monitor health of our connection to the metrics service
888 class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
binderDied(const wp<IBinder> &)889         virtual void binderDied(const wp<IBinder> &) {
890             ALOGW("Reacquire service connection on next request");
891             MediaAnalyticsItem::dropInstance();
892         }
893 };
894 
895 static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
896 
897 // static
dropInstance()898 void MediaAnalyticsItem::dropInstance() {
899     Mutex::Autolock _l(sInitMutex);
900     remainingBindAttempts = SVC_TRIES;
901     sAnalyticsService = NULL;
902 }
903 
904 //static
getInstance()905 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
906 
907     static const char *servicename = "media.metrics";
908     int enabled = isEnabled();
909 
910     if (enabled == false) {
911         if (DEBUG_SERVICEACCESS) {
912                 ALOGD("disabled");
913         }
914         return NULL;
915     }
916 
917     // completely skip logging from certain UIDs. We do this here
918     // to avoid the multi-second timeouts while we learn that
919     // sepolicy will not let us find the service.
920     // We do this only for a select set of UIDs
921     // The sepolicy protection is still in place, we just want a faster
922     // response from this specific, small set of uids.
923     {
924         uid_t uid = getuid();
925         switch (uid) {
926             case AID_RADIO:     // telephony subsystem, RIL
927                 return NULL;
928                 break;
929             default:
930                 // let sepolicy deny access if appropriate
931                 break;
932         }
933     }
934 
935     {
936         Mutex::Autolock _l(sInitMutex);
937         const char *badness = "";
938 
939         // think of remainingBindAttempts as telling us whether service==NULL because
940         // (1) we haven't tried to initialize it yet
941         // (2) we've tried to initialize it, but failed.
942         if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
943             sp<IServiceManager> sm = defaultServiceManager();
944             if (sm != NULL) {
945                 sp<IBinder> binder = sm->getService(String16(servicename));
946                 if (binder != NULL) {
947                     sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
948                     if (sNotifier != NULL) {
949                         sNotifier = NULL;
950                     }
951                     sNotifier = new MediaMetricsDeathNotifier();
952                     binder->linkToDeath(sNotifier);
953                 } else {
954                     badness = "did not find service";
955                 }
956             } else {
957                 badness = "No Service Manager access";
958             }
959 
960             if (sAnalyticsService == NULL) {
961                 if (remainingBindAttempts > 0) {
962                     remainingBindAttempts--;
963                 }
964                 if (DEBUG_SERVICEACCESS) {
965                     ALOGD("Unable to bind to service %s: %s", servicename, badness);
966                 }
967             }
968         }
969 
970         return sAnalyticsService;
971     }
972 }
973 
974 // merge the info from 'incoming' into this record.
975 // we finish with a union of this+incoming and special handling for collisions
merge(MediaAnalyticsItem * incoming)976 bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
977 
978     // if I don't have key or session id, take them from incoming
979     // 'this' should never be missing both of them...
980     if (mKey.empty()) {
981         mKey = incoming->mKey;
982     } else if (mSessionID == 0) {
983         mSessionID = incoming->mSessionID;
984     }
985 
986     // for each attribute from 'incoming', resolve appropriately
987     int nattr = incoming->mPropCount;
988     for (int i = 0 ; i < nattr; i++ ) {
989         Prop *iprop = &incoming->mProps[i];
990         const char *p = iprop->mName;
991         size_t len = strlen(p);
992 
993         // should ignore a zero length name...
994         if (len == 0) {
995             continue;
996         }
997 
998         Prop *oprop = findProp(iprop->mName);
999 
1000         if (oprop == NULL) {
1001             // no oprop, so we insert the new one
1002             oprop = allocateProp(p);
1003             if (oprop != NULL) {
1004                 copyProp(oprop, iprop);
1005             } else {
1006                 ALOGW("dropped property '%s'", iprop->mName);
1007             }
1008         } else {
1009             copyProp(oprop, iprop);
1010         }
1011     }
1012 
1013     // not sure when we'd return false...
1014     return true;
1015 }
1016 
1017 } // namespace android
1018 
1019