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 // So caller doesn't need to know size of allocated space
create()56 MediaAnalyticsItem *MediaAnalyticsItem::create()
57 {
58     return MediaAnalyticsItem::create(kKeyNone);
59 }
60 
create(MediaAnalyticsItem::Key key)61 MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
62 {
63     MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
64     return item;
65 }
66 
67 // access functions for the class
MediaAnalyticsItem()68 MediaAnalyticsItem::MediaAnalyticsItem()
69     : mPid(-1),
70       mUid(-1),
71       mPkgVersionCode(0),
72       mSessionID(MediaAnalyticsItem::SessionIDNone),
73       mTimestamp(0),
74       mFinalized(1),
75       mPropCount(0), mPropSize(0), mProps(NULL)
76 {
77     mKey = MediaAnalyticsItem::kKeyNone;
78 }
79 
MediaAnalyticsItem(MediaAnalyticsItem::Key key)80 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
81     : mPid(-1),
82       mUid(-1),
83       mPkgVersionCode(0),
84       mSessionID(MediaAnalyticsItem::SessionIDNone),
85       mTimestamp(0),
86       mFinalized(1),
87       mPropCount(0), mPropSize(0), mProps(NULL)
88 {
89     if (DEBUG_ALLOCATIONS) {
90         ALOGD("Allocate MediaAnalyticsItem @ %p", this);
91     }
92     mKey = key;
93 }
94 
~MediaAnalyticsItem()95 MediaAnalyticsItem::~MediaAnalyticsItem() {
96     if (DEBUG_ALLOCATIONS) {
97         ALOGD("Destroy  MediaAnalyticsItem @ %p", this);
98     }
99     clear();
100 }
101 
clear()102 void MediaAnalyticsItem::clear() {
103 
104     // clean allocated storage from key
105     mKey.clear();
106 
107     // clean various major parameters
108     mSessionID = MediaAnalyticsItem::SessionIDNone;
109 
110     // clean attributes
111     // contents of the attributes
112     for (size_t i = 0 ; i < mPropCount; i++ ) {
113         clearProp(&mProps[i]);
114     }
115     // the attribute records themselves
116     if (mProps != NULL) {
117         free(mProps);
118         mProps = NULL;
119     }
120     mPropSize = 0;
121     mPropCount = 0;
122 
123     return;
124 }
125 
126 // make a deep copy of myself
dup()127 MediaAnalyticsItem *MediaAnalyticsItem::dup() {
128     MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
129 
130     if (dst != NULL) {
131         // key as part of constructor
132         dst->mPid = this->mPid;
133         dst->mUid = this->mUid;
134         dst->mPkgName = this->mPkgName;
135         dst->mPkgVersionCode = this->mPkgVersionCode;
136         dst->mSessionID = this->mSessionID;
137         dst->mTimestamp = this->mTimestamp;
138         dst->mFinalized = this->mFinalized;
139 
140         // properties aka attributes
141         dst->growProps(this->mPropCount);
142         for(size_t i=0;i<mPropCount;i++) {
143             copyProp(&dst->mProps[i], &this->mProps[i]);
144         }
145         dst->mPropCount = this->mPropCount;
146     }
147 
148     return dst;
149 }
150 
setSessionID(MediaAnalyticsItem::SessionID_t id)151 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
152     mSessionID = id;
153     return *this;
154 }
155 
getSessionID() const156 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
157     return mSessionID;
158 }
159 
generateSessionID()160 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
161 
162     if (mSessionID == SessionIDNone) {
163         // get one from the server
164         MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
165         sp<IMediaAnalyticsService> svc = getInstance();
166         if (svc != NULL) {
167             newid = svc->generateUniqueSessionID();
168         }
169         mSessionID = newid;
170     }
171 
172     return mSessionID;
173 }
174 
clearSessionID()175 MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
176     mSessionID = MediaAnalyticsItem::SessionIDNone;
177     return *this;
178 }
179 
setTimestamp(nsecs_t ts)180 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
181     mTimestamp = ts;
182     return *this;
183 }
184 
getTimestamp() const185 nsecs_t MediaAnalyticsItem::getTimestamp() const {
186     return mTimestamp;
187 }
188 
setPid(pid_t pid)189 MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
190     mPid = pid;
191     return *this;
192 }
193 
getPid() const194 pid_t MediaAnalyticsItem::getPid() const {
195     return mPid;
196 }
197 
setUid(uid_t uid)198 MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
199     mUid = uid;
200     return *this;
201 }
202 
getUid() const203 uid_t MediaAnalyticsItem::getUid() const {
204     return mUid;
205 }
206 
setPkgName(const std::string & pkgName)207 MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
208     mPkgName = pkgName;
209     return *this;
210 }
211 
setPkgVersionCode(int64_t pkgVersionCode)212 MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
213     mPkgVersionCode = pkgVersionCode;
214     return *this;
215 }
216 
getPkgVersionCode() const217 int64_t MediaAnalyticsItem::getPkgVersionCode() const {
218     return mPkgVersionCode;
219 }
220 
221 // this key is for the overall record -- "codec", "player", "drm", etc
setKey(MediaAnalyticsItem::Key key)222 MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
223     mKey = key;
224     return *this;
225 }
226 
getKey()227 MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
228     return mKey;
229 }
230 
231 // number of attributes we have in this record
count() const232 int32_t MediaAnalyticsItem::count() const {
233     return mPropCount;
234 }
235 
236 // find the proper entry in the list
findPropIndex(const char * name,size_t len)237 size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
238 {
239     size_t i = 0;
240     for (; i < mPropCount; i++) {
241         Prop *prop = &mProps[i];
242         if (prop->mNameLen != len) {
243             continue;
244         }
245         if (memcmp(name, prop->mName, len) == 0) {
246             break;
247         }
248     }
249     return i;
250 }
251 
findProp(const char * name)252 MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
253     size_t len = strlen(name);
254     size_t i = findPropIndex(name, len);
255     if (i < mPropCount) {
256         return &mProps[i];
257     }
258     return NULL;
259 }
260 
setName(const char * name,size_t len)261 void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
262     free((void *)mName);
263     mName = (const char *) malloc(len+1);
264     LOG_ALWAYS_FATAL_IF(mName == NULL,
265                         "failed malloc() for property '%s' (len %zu)",
266                         name, len);
267     memcpy ((void *)mName, name, len+1);
268     mNameLen = len;
269 }
270 
271 // consider this "find-or-allocate".
272 // caller validates type and uses clearPropValue() accordingly
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             if (growProps() == false) {
283                 ALOGE("failed allocation for new props");
284                 return NULL;
285             }
286         }
287         i = mPropCount++;
288         prop = &mProps[i];
289         prop->setName(name, len);
290     }
291 
292     return prop;
293 }
294 
295 // used within the summarizers; return whether property existed
removeProp(const char * name)296 bool MediaAnalyticsItem::removeProp(const char *name) {
297     size_t len = strlen(name);
298     size_t i = findPropIndex(name, len);
299     if (i < mPropCount) {
300         Prop *prop = &mProps[i];
301         clearProp(prop);
302         if (i != mPropCount-1) {
303             // in the middle, bring last one down to fill gap
304             copyProp(prop, &mProps[mPropCount-1]);
305             clearProp(&mProps[mPropCount-1]);
306         }
307         mPropCount--;
308         return true;
309     }
310     return false;
311 }
312 
313 // set the values
setInt32(MediaAnalyticsItem::Attr name,int32_t value)314 void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
315     Prop *prop = allocateProp(name);
316     if (prop != NULL) {
317         clearPropValue(prop);
318         prop->mType = kTypeInt32;
319         prop->u.int32Value = value;
320     }
321 }
322 
setInt64(MediaAnalyticsItem::Attr name,int64_t value)323 void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
324     Prop *prop = allocateProp(name);
325     if (prop != NULL) {
326         clearPropValue(prop);
327         prop->mType = kTypeInt64;
328         prop->u.int64Value = value;
329     }
330 }
331 
setDouble(MediaAnalyticsItem::Attr name,double value)332 void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
333     Prop *prop = allocateProp(name);
334     if (prop != NULL) {
335         clearPropValue(prop);
336         prop->mType = kTypeDouble;
337         prop->u.doubleValue = value;
338     }
339 }
340 
setCString(MediaAnalyticsItem::Attr name,const char * value)341 void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
342 
343     Prop *prop = allocateProp(name);
344     // any old value will be gone
345     if (prop != NULL) {
346         clearPropValue(prop);
347         prop->mType = kTypeCString;
348         prop->u.CStringValue = strdup(value);
349     }
350 }
351 
setRate(MediaAnalyticsItem::Attr name,int64_t count,int64_t duration)352 void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
353     Prop *prop = allocateProp(name);
354     if (prop != NULL) {
355         clearPropValue(prop);
356         prop->mType = kTypeRate;
357         prop->u.rate.count = count;
358         prop->u.rate.duration = duration;
359     }
360 }
361 
362 
363 // find/add/set fused into a single operation
addInt32(MediaAnalyticsItem::Attr name,int32_t value)364 void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
365     Prop *prop = allocateProp(name);
366     if (prop == NULL) {
367         return;
368     }
369     switch (prop->mType) {
370         case kTypeInt32:
371             prop->u.int32Value += value;
372             break;
373         default:
374             clearPropValue(prop);
375             prop->mType = kTypeInt32;
376             prop->u.int32Value = value;
377             break;
378     }
379 }
380 
addInt64(MediaAnalyticsItem::Attr name,int64_t value)381 void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
382     Prop *prop = allocateProp(name);
383     if (prop == NULL) {
384         return;
385     }
386     switch (prop->mType) {
387         case kTypeInt64:
388             prop->u.int64Value += value;
389             break;
390         default:
391             clearPropValue(prop);
392             prop->mType = kTypeInt64;
393             prop->u.int64Value = value;
394             break;
395     }
396 }
397 
addRate(MediaAnalyticsItem::Attr name,int64_t count,int64_t duration)398 void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
399     Prop *prop = allocateProp(name);
400     if (prop == NULL) {
401         return;
402     }
403     switch (prop->mType) {
404         case kTypeRate:
405             prop->u.rate.count += count;
406             prop->u.rate.duration += duration;
407             break;
408         default:
409             clearPropValue(prop);
410             prop->mType = kTypeRate;
411             prop->u.rate.count = count;
412             prop->u.rate.duration = duration;
413             break;
414     }
415 }
416 
addDouble(MediaAnalyticsItem::Attr name,double value)417 void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
418     Prop *prop = allocateProp(name);
419     if (prop == NULL) {
420         return;
421     }
422     switch (prop->mType) {
423         case kTypeDouble:
424             prop->u.doubleValue += value;
425             break;
426         default:
427             clearPropValue(prop);
428             prop->mType = kTypeDouble;
429             prop->u.doubleValue = value;
430             break;
431     }
432 }
433 
434 // find & extract values
getInt32(MediaAnalyticsItem::Attr name,int32_t * value)435 bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
436     Prop *prop = findProp(name);
437     if (prop == NULL || prop->mType != kTypeInt32) {
438         return false;
439     }
440     if (value != NULL) {
441         *value = prop->u.int32Value;
442     }
443     return true;
444 }
445 
getInt64(MediaAnalyticsItem::Attr name,int64_t * value)446 bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
447     Prop *prop = findProp(name);
448     if (prop == NULL || prop->mType != kTypeInt64) {
449         return false;
450     }
451     if (value != NULL) {
452         *value = prop->u.int64Value;
453     }
454     return true;
455 }
456 
getRate(MediaAnalyticsItem::Attr name,int64_t * count,int64_t * duration,double * rate)457 bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
458     Prop *prop = findProp(name);
459     if (prop == NULL || prop->mType != kTypeRate) {
460         return false;
461     }
462     if (count != NULL) {
463         *count = prop->u.rate.count;
464     }
465     if (duration != NULL) {
466         *duration = prop->u.rate.duration;
467     }
468     if (rate != NULL) {
469         double r = 0.0;
470         if (prop->u.rate.duration != 0) {
471             r = prop->u.rate.count / (double) prop->u.rate.duration;
472         }
473         *rate = r;
474     }
475     return true;
476 }
477 
getDouble(MediaAnalyticsItem::Attr name,double * value)478 bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
479     Prop *prop = findProp(name);
480     if (prop == NULL || prop->mType != kTypeDouble) {
481         return false;
482     }
483     if (value != NULL) {
484         *value = prop->u.doubleValue;
485     }
486     return true;
487 }
488 
489 // caller responsible for the returned string
getCString(MediaAnalyticsItem::Attr name,char ** value)490 bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
491     Prop *prop = findProp(name);
492     if (prop == NULL || prop->mType != kTypeCString) {
493         return false;
494     }
495     if (value != NULL) {
496         *value = strdup(prop->u.CStringValue);
497     }
498     return true;
499 }
500 
getString(MediaAnalyticsItem::Attr name,std::string * value)501 bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
502     Prop *prop = findProp(name);
503     if (prop == NULL || prop->mType != kTypeCString) {
504         return false;
505     }
506     if (value != NULL) {
507         // std::string makes a copy for us
508         *value = prop->u.CStringValue;
509     }
510     return true;
511 }
512 
513 // remove indicated keys and their values
514 // return value is # keys removed
filter(int n,MediaAnalyticsItem::Attr attrs[])515 int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
516     int zapped = 0;
517     if (attrs == NULL || n <= 0) {
518         return -1;
519     }
520     for (ssize_t i = 0 ; i < n ;  i++) {
521         const char *name = attrs[i];
522         size_t len = strlen(name);
523         size_t j = findPropIndex(name, len);
524         if (j >= mPropCount) {
525             // not there
526             continue;
527         } else if (j+1 == mPropCount) {
528             // last one, shorten
529             zapped++;
530             clearProp(&mProps[j]);
531             mPropCount--;
532         } else {
533             // in the middle, bring last one down and shorten
534             zapped++;
535             clearProp(&mProps[j]);
536             mProps[j] = mProps[mPropCount-1];
537             mPropCount--;
538         }
539     }
540     return zapped;
541 }
542 
543 // remove any keys NOT in the provided list
544 // return value is # keys removed
filterNot(int n,MediaAnalyticsItem::Attr attrs[])545 int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
546     int zapped = 0;
547     if (attrs == NULL || n <= 0) {
548         return -1;
549     }
550     for (ssize_t i = mPropCount-1 ; i >=0 ;  i--) {
551         Prop *prop = &mProps[i];
552         for (ssize_t j = 0; j < n ; j++) {
553             if (strcmp(prop->mName, attrs[j]) == 0) {
554                 clearProp(prop);
555                 zapped++;
556                 if (i != (ssize_t)(mPropCount-1)) {
557                     *prop = mProps[mPropCount-1];
558                 }
559                 initProp(&mProps[mPropCount-1]);
560                 mPropCount--;
561                 break;
562             }
563         }
564     }
565     return zapped;
566 }
567 
568 // remove a single key
569 // return value is 0 (not found) or 1 (found and removed)
filter(MediaAnalyticsItem::Attr name)570 int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
571     return filter(1, &name);
572 }
573 
574 // handle individual items/properties stored within the class
575 //
576 
initProp(Prop * prop)577 void MediaAnalyticsItem::initProp(Prop *prop) {
578     if (prop != NULL) {
579         prop->mName = NULL;
580         prop->mNameLen = 0;
581 
582         prop->mType = kTypeNone;
583     }
584 }
585 
clearProp(Prop * prop)586 void MediaAnalyticsItem::clearProp(Prop *prop)
587 {
588     if (prop != NULL) {
589         if (prop->mName != NULL) {
590             free((void *)prop->mName);
591             prop->mName = NULL;
592             prop->mNameLen = 0;
593         }
594 
595         clearPropValue(prop);
596     }
597 }
598 
clearPropValue(Prop * prop)599 void MediaAnalyticsItem::clearPropValue(Prop *prop)
600 {
601     if (prop != NULL) {
602         if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
603             free(prop->u.CStringValue);
604             prop->u.CStringValue = NULL;
605         }
606         prop->mType = kTypeNone;
607     }
608 }
609 
copyProp(Prop * dst,const Prop * src)610 void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
611 {
612     // get rid of any pointers in the dst
613     clearProp(dst);
614 
615     *dst = *src;
616 
617     // fix any pointers that we blindly copied, so we have our own copies
618     if (dst->mName) {
619         void *p =  malloc(dst->mNameLen + 1);
620         LOG_ALWAYS_FATAL_IF(p == NULL,
621                             "failed malloc() duping property '%s' (len %zu)",
622                             dst->mName, dst->mNameLen);
623         memcpy (p, src->mName, dst->mNameLen + 1);
624         dst->mName = (const char *) p;
625     }
626     if (dst->mType == kTypeCString) {
627         dst->u.CStringValue = strdup(src->u.CStringValue);
628     }
629 }
630 
growProps(int increment)631 bool MediaAnalyticsItem::growProps(int increment)
632 {
633     if (increment <= 0) {
634         increment = kGrowProps;
635     }
636     int nsize = mPropSize + increment;
637     Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
638 
639     if (ni != NULL) {
640         for (int i = mPropSize; i < nsize; i++) {
641             initProp(&ni[i]);
642         }
643         mProps = ni;
644         mPropSize = nsize;
645         return true;
646     } else {
647         ALOGW("MediaAnalyticsItem::growProps fails");
648         return false;
649     }
650 }
651 
652 // Parcel / serialize things for binder calls
653 //
654 
readFromParcel(const Parcel & data)655 int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
656     int32_t version = data.readInt32();
657 
658     switch(version) {
659         case 0:
660           return readFromParcel0(data);
661           break;
662         default:
663           ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
664           return -1;
665     }
666 }
667 
readFromParcel0(const Parcel & data)668 int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
669     // into 'this' object
670     // .. we make a copy of the string to put away.
671     mKey = data.readCString();
672     mPid = data.readInt32();
673     mUid = data.readInt32();
674     mPkgName = data.readCString();
675     mPkgVersionCode = data.readInt64();
676     mSessionID = data.readInt64();
677     // We no longer pay attention to user setting of finalized, BUT it's
678     // still part of the wire packet -- so read & discard.
679     mFinalized = data.readInt32();
680     mFinalized = 1;
681     mTimestamp = data.readInt64();
682 
683     int count = data.readInt32();
684     for (int i = 0; i < count ; i++) {
685             MediaAnalyticsItem::Attr attr = data.readCString();
686             int32_t ztype = data.readInt32();
687                 switch (ztype) {
688                     case MediaAnalyticsItem::kTypeInt32:
689                             setInt32(attr, data.readInt32());
690                             break;
691                     case MediaAnalyticsItem::kTypeInt64:
692                             setInt64(attr, data.readInt64());
693                             break;
694                     case MediaAnalyticsItem::kTypeDouble:
695                             setDouble(attr, data.readDouble());
696                             break;
697                     case MediaAnalyticsItem::kTypeCString:
698                             setCString(attr, data.readCString());
699                             break;
700                     case MediaAnalyticsItem::kTypeRate:
701                             {
702                                 int64_t count = data.readInt64();
703                                 int64_t duration = data.readInt64();
704                                 setRate(attr, count, duration);
705                             }
706                             break;
707                     default:
708                             ALOGE("reading bad item type: %d, idx %d",
709                                   ztype, i);
710                             return -1;
711                 }
712     }
713 
714     return 0;
715 }
716 
writeToParcel(Parcel * data)717 int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
718 
719     if (data == NULL) return -1;
720 
721     int32_t version = 0;
722     data->writeInt32(version);
723 
724     switch(version) {
725         case 0:
726           return writeToParcel0(data);
727           break;
728         default:
729           ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
730           return -1;
731     }
732 }
733 
writeToParcel0(Parcel * data)734 int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
735 
736     data->writeCString(mKey.c_str());
737     data->writeInt32(mPid);
738     data->writeInt32(mUid);
739     data->writeCString(mPkgName.c_str());
740     data->writeInt64(mPkgVersionCode);
741     data->writeInt64(mSessionID);
742     data->writeInt32(mFinalized);
743     data->writeInt64(mTimestamp);
744 
745     // set of items
746     int count = mPropCount;
747     data->writeInt32(count);
748     for (int i = 0 ; i < count; i++ ) {
749             Prop *prop = &mProps[i];
750             data->writeCString(prop->mName);
751             data->writeInt32(prop->mType);
752             switch (prop->mType) {
753                 case MediaAnalyticsItem::kTypeInt32:
754                         data->writeInt32(prop->u.int32Value);
755                         break;
756                 case MediaAnalyticsItem::kTypeInt64:
757                         data->writeInt64(prop->u.int64Value);
758                         break;
759                 case MediaAnalyticsItem::kTypeDouble:
760                         data->writeDouble(prop->u.doubleValue);
761                         break;
762                 case MediaAnalyticsItem::kTypeRate:
763                         data->writeInt64(prop->u.rate.count);
764                         data->writeInt64(prop->u.rate.duration);
765                         break;
766                 case MediaAnalyticsItem::kTypeCString:
767                         data->writeCString(prop->u.CStringValue);
768                         break;
769                 default:
770                         ALOGE("found bad Prop type: %d, idx %d, name %s",
771                               prop->mType, i, prop->mName);
772                         break;
773             }
774     }
775 
776     return 0;
777 }
778 
toCString()779 const char *MediaAnalyticsItem::toCString() {
780    return toCString(PROTO_LAST);
781 }
782 
toCString(int version)783 const char * MediaAnalyticsItem::toCString(int version) {
784     std::string val = toString(version);
785     return strdup(val.c_str());
786 }
787 
toString()788 std::string MediaAnalyticsItem::toString() {
789    return toString(PROTO_LAST);
790 }
791 
toString(int version)792 std::string MediaAnalyticsItem::toString(int version) {
793 
794     // v0 : released with 'o'
795     // v1 : bug fix (missing pid/finalized separator),
796     //      adds apk name, apk version code
797 
798     if (version <= PROTO_FIRST) {
799         // default to original v0 format, until proper parsers are in place
800         version = PROTO_V0;
801     } else if (version > PROTO_LAST) {
802         version = PROTO_LAST;
803     }
804 
805     std::string result;
806     char buffer[512];
807 
808     if (version == PROTO_V0) {
809         result = "(";
810     } else {
811         snprintf(buffer, sizeof(buffer), "[%d:", version);
812         result.append(buffer);
813     }
814 
815     // same order as we spill into the parcel, although not required
816     // key+session are our primary matching criteria
817     result.append(mKey.c_str());
818     result.append(":");
819     snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
820     result.append(buffer);
821 
822     snprintf(buffer, sizeof(buffer), "%d:", mUid);
823     result.append(buffer);
824 
825     if (version >= PROTO_V1) {
826         result.append(mPkgName);
827         snprintf(buffer, sizeof(buffer), ":%"  PRId64 ":", mPkgVersionCode);
828         result.append(buffer);
829     }
830 
831     // in 'o' (v1) , the separator between pid and finalized was omitted
832     if (version <= PROTO_V0) {
833         snprintf(buffer, sizeof(buffer), "%d", mPid);
834     } else {
835         snprintf(buffer, sizeof(buffer), "%d:", mPid);
836     }
837     result.append(buffer);
838 
839     snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
840     result.append(buffer);
841     snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
842     result.append(buffer);
843 
844     // set of items
845     int count = mPropCount;
846     snprintf(buffer, sizeof(buffer), "%d:", count);
847     result.append(buffer);
848     for (int i = 0 ; i < count; i++ ) {
849             Prop *prop = &mProps[i];
850             switch (prop->mType) {
851                 case MediaAnalyticsItem::kTypeInt32:
852                         snprintf(buffer,sizeof(buffer),
853                         "%s=%d:", prop->mName, prop->u.int32Value);
854                         break;
855                 case MediaAnalyticsItem::kTypeInt64:
856                         snprintf(buffer,sizeof(buffer),
857                         "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
858                         break;
859                 case MediaAnalyticsItem::kTypeDouble:
860                         snprintf(buffer,sizeof(buffer),
861                         "%s=%e:", prop->mName, prop->u.doubleValue);
862                         break;
863                 case MediaAnalyticsItem::kTypeRate:
864                         snprintf(buffer,sizeof(buffer),
865                         "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
866                         prop->u.rate.count, prop->u.rate.duration);
867                         break;
868                 case MediaAnalyticsItem::kTypeCString:
869                         snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
870                         result.append(buffer);
871                         // XXX: sanitize string for ':' '='
872                         result.append(prop->u.CStringValue);
873                         buffer[0] = ':';
874                         buffer[1] = '\0';
875                         break;
876                 default:
877                         ALOGE("to_String bad item type: %d for %s",
878                               prop->mType, prop->mName);
879                         break;
880             }
881             result.append(buffer);
882     }
883 
884     if (version == PROTO_V0) {
885         result.append(")");
886     } else {
887         result.append("]");
888     }
889 
890     return result;
891 }
892 
893 // for the lazy, we offer methods that finds the service and
894 // calls the appropriate daemon
selfrecord()895 bool MediaAnalyticsItem::selfrecord() {
896     return selfrecord(false);
897 }
898 
selfrecord(bool forcenew)899 bool MediaAnalyticsItem::selfrecord(bool forcenew) {
900 
901     if (DEBUG_API) {
902         std::string p = this->toString();
903         ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
904     }
905 
906     sp<IMediaAnalyticsService> svc = getInstance();
907 
908     if (svc != NULL) {
909         MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
910         if (newid == SessionIDInvalid) {
911             std::string p = this->toString();
912             ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
913             return false;
914         }
915         return true;
916     } else {
917         return false;
918     }
919 }
920 
921 // get a connection we can reuse for most of our lifetime
922 // static
923 sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
924 static Mutex sInitMutex;
925 static int remainingBindAttempts = SVC_TRIES;
926 
927 //static
isEnabled()928 bool MediaAnalyticsItem::isEnabled() {
929     int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
930 
931     if (enabled == -1) {
932         enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
933     }
934     if (enabled == -1) {
935         enabled = MediaAnalyticsItem::EnabledProperty_default;
936     }
937     if (enabled <= 0) {
938         return false;
939     }
940     return true;
941 }
942 
943 
944 // monitor health of our connection to the metrics service
945 class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
binderDied(const wp<IBinder> &)946         virtual void binderDied(const wp<IBinder> &) {
947             ALOGW("Reacquire service connection on next request");
948             MediaAnalyticsItem::dropInstance();
949         }
950 };
951 
952 static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
953 
954 // static
dropInstance()955 void MediaAnalyticsItem::dropInstance() {
956     Mutex::Autolock _l(sInitMutex);
957     remainingBindAttempts = SVC_TRIES;
958     sAnalyticsService = NULL;
959 }
960 
961 //static
getInstance()962 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
963 
964     static const char *servicename = "media.metrics";
965     int enabled = isEnabled();
966 
967     if (enabled == false) {
968         if (DEBUG_SERVICEACCESS) {
969                 ALOGD("disabled");
970         }
971         return NULL;
972     }
973 
974     // completely skip logging from certain UIDs. We do this here
975     // to avoid the multi-second timeouts while we learn that
976     // sepolicy will not let us find the service.
977     // We do this only for a select set of UIDs
978     // The sepolicy protection is still in place, we just want a faster
979     // response from this specific, small set of uids.
980     {
981         uid_t uid = getuid();
982         switch (uid) {
983             case AID_RADIO:     // telephony subsystem, RIL
984                 return NULL;
985                 break;
986             default:
987                 // let sepolicy deny access if appropriate
988                 break;
989         }
990     }
991 
992     {
993         Mutex::Autolock _l(sInitMutex);
994         const char *badness = "";
995 
996         // think of remainingBindAttempts as telling us whether service==NULL because
997         // (1) we haven't tried to initialize it yet
998         // (2) we've tried to initialize it, but failed.
999         if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
1000             sp<IServiceManager> sm = defaultServiceManager();
1001             if (sm != NULL) {
1002                 sp<IBinder> binder = sm->getService(String16(servicename));
1003                 if (binder != NULL) {
1004                     sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
1005                     if (sNotifier != NULL) {
1006                         sNotifier = NULL;
1007                     }
1008                     sNotifier = new MediaMetricsDeathNotifier();
1009                     binder->linkToDeath(sNotifier);
1010                 } else {
1011                     badness = "did not find service";
1012                 }
1013             } else {
1014                 badness = "No Service Manager access";
1015             }
1016 
1017             if (sAnalyticsService == NULL) {
1018                 if (remainingBindAttempts > 0) {
1019                     remainingBindAttempts--;
1020                 }
1021                 if (DEBUG_SERVICEACCESS) {
1022                     ALOGD("Unable to bind to service %s: %s", servicename, badness);
1023                 }
1024             }
1025         }
1026 
1027         return sAnalyticsService;
1028     }
1029 }
1030 
1031 // merge the info from 'incoming' into this record.
1032 // we finish with a union of this+incoming and special handling for collisions
merge(MediaAnalyticsItem * incoming)1033 bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
1034 
1035     // if I don't have key or session id, take them from incoming
1036     // 'this' should never be missing both of them...
1037     if (mKey.empty()) {
1038         mKey = incoming->mKey;
1039     } else if (mSessionID == 0) {
1040         mSessionID = incoming->mSessionID;
1041     }
1042 
1043     // for each attribute from 'incoming', resolve appropriately
1044     int nattr = incoming->mPropCount;
1045     for (int i = 0 ; i < nattr; i++ ) {
1046         Prop *iprop = &incoming->mProps[i];
1047         const char *p = iprop->mName;
1048         size_t len = strlen(p);
1049 
1050         // should ignore a zero length name...
1051         if (len == 0) {
1052             continue;
1053         }
1054 
1055         Prop *oprop = findProp(iprop->mName);
1056 
1057         if (oprop == NULL) {
1058             // no oprop, so we insert the new one
1059             oprop = allocateProp(p);
1060             if (oprop != NULL) {
1061                 copyProp(oprop, iprop);
1062             } else {
1063                 ALOGW("dropped property '%s'", iprop->mName);
1064             }
1065         } else {
1066             copyProp(oprop, iprop);
1067         }
1068     }
1069 
1070     // not sure when we'd return false...
1071     return true;
1072 }
1073 
1074 // a byte array; contents are
1075 // overall length (uint32) including the length field itself
1076 // encoding version (uint32)
1077 // count of properties (uint32)
1078 // N copies of:
1079 //     property name as length(int16), bytes
1080 //         the bytes WILL include the null terminator of the name
1081 //     type (uint8 -- 1 byte)
1082 //     size of value field (int16 -- 2 bytes)
1083 //     value (size based on type)
1084 //       int32, int64, double -- little endian 4/8/8 bytes respectively
1085 //       cstring -- N bytes of value [WITH terminator]
1086 
1087 enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
1088 
dumpAttributes(char ** pbuffer,size_t * plength)1089 bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
1090 
1091     char *build = NULL;
1092 
1093     if (pbuffer == NULL || plength == NULL)
1094         return false;
1095 
1096     // consistency for the caller, who owns whatever comes back in this pointer.
1097     *pbuffer = NULL;
1098 
1099     // first, let's calculate sizes
1100     int32_t goal = 0;
1101     int32_t version = 0;
1102 
1103     goal += sizeof(uint32_t);   // overall length, including the length field
1104     goal += sizeof(uint32_t);   // encoding version
1105     goal += sizeof(uint32_t);   // # properties
1106 
1107     int32_t count = mPropCount;
1108     for (int i = 0 ; i < count; i++ ) {
1109         Prop *prop = &mProps[i];
1110         goal += sizeof(uint16_t);           // name length
1111         goal += strlen(prop->mName) + 1;    // string + null
1112         goal += sizeof(uint8_t);            // type
1113         goal += sizeof(uint16_t);           // size of value
1114         switch (prop->mType) {
1115             case MediaAnalyticsItem::kTypeInt32:
1116                     goal += sizeof(uint32_t);
1117                     break;
1118             case MediaAnalyticsItem::kTypeInt64:
1119                     goal += sizeof(uint64_t);
1120                     break;
1121             case MediaAnalyticsItem::kTypeDouble:
1122                     goal += sizeof(double);
1123                     break;
1124             case MediaAnalyticsItem::kTypeRate:
1125                     goal += 2 * sizeof(uint64_t);
1126                     break;
1127             case MediaAnalyticsItem::kTypeCString:
1128                     // length + actual string + null
1129                     goal += strlen(prop->u.CStringValue) + 1;
1130                     break;
1131             default:
1132                     ALOGE("found bad Prop type: %d, idx %d, name %s",
1133                           prop->mType, i, prop->mName);
1134                     return false;
1135         }
1136     }
1137 
1138     // now that we have a size... let's allocate and fill
1139     build = (char *)malloc(goal);
1140     if (build == NULL)
1141         return false;
1142 
1143     memset(build, 0, goal);
1144 
1145     char *filling = build;
1146 
1147 #define _INSERT(val, size) \
1148     { memcpy(filling, &(val), (size)); filling += (size);}
1149 #define _INSERTSTRING(val, size) \
1150     { memcpy(filling, (val), (size)); filling += (size);}
1151 
1152     _INSERT(goal, sizeof(int32_t));
1153     _INSERT(version, sizeof(int32_t));
1154     _INSERT(count, sizeof(int32_t));
1155 
1156     for (int i = 0 ; i < count; i++ ) {
1157         Prop *prop = &mProps[i];
1158         int16_t attrNameLen = strlen(prop->mName) + 1;
1159         _INSERT(attrNameLen, sizeof(int16_t));
1160         _INSERTSTRING(prop->mName, attrNameLen);    // termination included
1161         int8_t elemtype;
1162         int16_t elemsize;
1163         switch (prop->mType) {
1164             case MediaAnalyticsItem::kTypeInt32:
1165                 {
1166                     elemtype = kInt32;
1167                     _INSERT(elemtype, sizeof(int8_t));
1168                     elemsize = sizeof(int32_t);
1169                     _INSERT(elemsize, sizeof(int16_t));
1170 
1171                     _INSERT(prop->u.int32Value, sizeof(int32_t));
1172                     break;
1173                 }
1174             case MediaAnalyticsItem::kTypeInt64:
1175                 {
1176                     elemtype = kInt64;
1177                     _INSERT(elemtype, sizeof(int8_t));
1178                     elemsize = sizeof(int64_t);
1179                     _INSERT(elemsize, sizeof(int16_t));
1180 
1181                     _INSERT(prop->u.int64Value, sizeof(int64_t));
1182                     break;
1183                 }
1184             case MediaAnalyticsItem::kTypeDouble:
1185                 {
1186                     elemtype = kDouble;
1187                     _INSERT(elemtype, sizeof(int8_t));
1188                     elemsize = sizeof(double);
1189                     _INSERT(elemsize, sizeof(int16_t));
1190 
1191                     _INSERT(prop->u.doubleValue, sizeof(double));
1192                     break;
1193                 }
1194             case MediaAnalyticsItem::kTypeRate:
1195                 {
1196                     elemtype = kRate;
1197                     _INSERT(elemtype, sizeof(int8_t));
1198                     elemsize = 2 * sizeof(uint64_t);
1199                     _INSERT(elemsize, sizeof(int16_t));
1200 
1201                     _INSERT(prop->u.rate.count, sizeof(uint64_t));
1202                     _INSERT(prop->u.rate.duration, sizeof(uint64_t));
1203                     break;
1204                 }
1205             case MediaAnalyticsItem::kTypeCString:
1206                 {
1207                     elemtype = kCString;
1208                     _INSERT(elemtype, sizeof(int8_t));
1209                     elemsize = strlen(prop->u.CStringValue) + 1;
1210                     _INSERT(elemsize, sizeof(int16_t));
1211 
1212                     _INSERTSTRING(prop->u.CStringValue, elemsize);
1213                     break;
1214                 }
1215             default:
1216                     // error if can't encode; warning if can't decode
1217                     ALOGE("found bad Prop type: %d, idx %d, name %s",
1218                           prop->mType, i, prop->mName);
1219                     goto badness;
1220         }
1221     }
1222 
1223     if (build + goal != filling) {
1224         ALOGE("problems populating; wrote=%d planned=%d",
1225               (int)(filling-build), goal);
1226         goto badness;
1227     }
1228 
1229     *pbuffer = build;
1230     *plength = goal;
1231 
1232     return true;
1233 
1234   badness:
1235     free(build);
1236     return false;
1237 }
1238 
1239 } // namespace android
1240 
1241