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