Home | History | Annotate | Download | only in libmediametrics
      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
     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 
     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 
     86 MediaAnalyticsItem::~MediaAnalyticsItem() {
     87     if (DEBUG_ALLOCATIONS) {
     88         ALOGD("Destroy  MediaAnalyticsItem @ %p", this);
     89     }
     90     clear();
     91 }
     92 
     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
    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
    143 MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
    144     mFinalized = value;
    145     return *this;
    146 }
    147 
    148 bool MediaAnalyticsItem::getFinalized() const {
    149     return mFinalized;
    150 }
    151 
    152 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
    153     mSessionID = id;
    154     return *this;
    155 }
    156 
    157 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
    158     return mSessionID;
    159 }
    160 
    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 
    176 MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
    177     mSessionID = MediaAnalyticsItem::SessionIDNone;
    178     return *this;
    179 }
    180 
    181 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
    182     mTimestamp = ts;
    183     return *this;
    184 }
    185 
    186 nsecs_t MediaAnalyticsItem::getTimestamp() const {
    187     return mTimestamp;
    188 }
    189 
    190 MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
    191     mPid = pid;
    192     return *this;
    193 }
    194 
    195 pid_t MediaAnalyticsItem::getPid() const {
    196     return mPid;
    197 }
    198 
    199 MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
    200     mUid = uid;
    201     return *this;
    202 }
    203 
    204 uid_t MediaAnalyticsItem::getUid() const {
    205     return mUid;
    206 }
    207 
    208 MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
    209     mPkgName = pkgName;
    210     return *this;
    211 }
    212 
    213 AString MediaAnalyticsItem::getPkgName() const {
    214     return mPkgName;
    215 }
    216 
    217 MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int32_t pkgVersionCode) {
    218     mPkgVersionCode = pkgVersionCode;
    219     return *this;
    220 }
    221 
    222 int32_t MediaAnalyticsItem::getPkgVersionCode() const {
    223     return mPkgVersionCode;
    224 }
    225 
    226 // this key is for the overall record -- "codec", "player", "drm", etc
    227 MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
    228     mKey = key;
    229     return *this;
    230 }
    231 
    232 MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
    233     return mKey;
    234 }
    235 
    236 // number of attributes we have in this record
    237 int32_t MediaAnalyticsItem::count() const {
    238     return mPropCount;
    239 }
    240 
    241 // find the proper entry in the list
    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 
    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 
    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
    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
    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
    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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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
    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
    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
    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)
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    702 AString MediaAnalyticsItem::toString() {
    703    return toString(-1);
    704 }
    705 
    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
    809 bool MediaAnalyticsItem::selfrecord() {
    810     return selfrecord(false);
    811 }
    812 
    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
    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 {
    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
    871 void MediaAnalyticsItem::dropInstance() {
    872     Mutex::Autolock _l(sInitMutex);
    873     remainingBindAttempts = SVC_TRIES;
    874     sAnalyticsService = NULL;
    875 }
    876 
    877 //static
    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
    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