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