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 // So caller doesn't need to know size of allocated space
     56 MediaAnalyticsItem *MediaAnalyticsItem::create()
     57 {
     58     return MediaAnalyticsItem::create(kKeyNone);
     59 }
     60 
     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
     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 
     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 
     95 MediaAnalyticsItem::~MediaAnalyticsItem() {
     96     if (DEBUG_ALLOCATIONS) {
     97         ALOGD("Destroy  MediaAnalyticsItem @ %p", this);
     98     }
     99     clear();
    100 }
    101 
    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
    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 
    151 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
    152     mSessionID = id;
    153     return *this;
    154 }
    155 
    156 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
    157     return mSessionID;
    158 }
    159 
    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 
    175 MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
    176     mSessionID = MediaAnalyticsItem::SessionIDNone;
    177     return *this;
    178 }
    179 
    180 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
    181     mTimestamp = ts;
    182     return *this;
    183 }
    184 
    185 nsecs_t MediaAnalyticsItem::getTimestamp() const {
    186     return mTimestamp;
    187 }
    188 
    189 MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) {
    190     mPid = pid;
    191     return *this;
    192 }
    193 
    194 pid_t MediaAnalyticsItem::getPid() const {
    195     return mPid;
    196 }
    197 
    198 MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) {
    199     mUid = uid;
    200     return *this;
    201 }
    202 
    203 uid_t MediaAnalyticsItem::getUid() const {
    204     return mUid;
    205 }
    206 
    207 MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) {
    208     mPkgName = pkgName;
    209     return *this;
    210 }
    211 
    212 MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) {
    213     mPkgVersionCode = pkgVersionCode;
    214     return *this;
    215 }
    216 
    217 int64_t MediaAnalyticsItem::getPkgVersionCode() const {
    218     return mPkgVersionCode;
    219 }
    220 
    221 // this key is for the overall record -- "codec", "player", "drm", etc
    222 MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
    223     mKey = key;
    224     return *this;
    225 }
    226 
    227 MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
    228     return mKey;
    229 }
    230 
    231 // number of attributes we have in this record
    232 int32_t MediaAnalyticsItem::count() const {
    233     return mPropCount;
    234 }
    235 
    236 // find the proper entry in the list
    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 
    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 
    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
    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
    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
    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 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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
    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 
    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 
    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 
    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
    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 
    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
    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
    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)
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    779 const char *MediaAnalyticsItem::toCString() {
    780    return toCString(PROTO_LAST);
    781 }
    782 
    783 const char * MediaAnalyticsItem::toCString(int version) {
    784     std::string val = toString(version);
    785     return strdup(val.c_str());
    786 }
    787 
    788 std::string MediaAnalyticsItem::toString() {
    789    return toString(PROTO_LAST);
    790 }
    791 
    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
    895 bool MediaAnalyticsItem::selfrecord() {
    896     return selfrecord(false);
    897 }
    898 
    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
    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 {
    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
    955 void MediaAnalyticsItem::dropInstance() {
    956     Mutex::Autolock _l(sInitMutex);
    957     remainingBindAttempts = SVC_TRIES;
    958     sAnalyticsService = NULL;
    959 }
    960 
    961 //static
    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
   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 
   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