Home | History | Annotate | Download | only in mediaanalytics
      1 /*
      2  * Copyright (C) 2017 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 // Proxy for media player implementations
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "MediaAnalyticsService"
     21 #include <utils/Log.h>
     22 
     23 #include <stdint.h>
     24 #include <inttypes.h>
     25 #include <sys/types.h>
     26 #include <sys/stat.h>
     27 #include <sys/time.h>
     28 #include <dirent.h>
     29 #include <unistd.h>
     30 
     31 #include <string.h>
     32 #include <pwd.h>
     33 
     34 #include <cutils/atomic.h>
     35 #include <cutils/properties.h> // for property_get
     36 
     37 #include <utils/misc.h>
     38 
     39 #include <android/content/pm/IPackageManagerNative.h>
     40 
     41 #include <binder/IPCThreadState.h>
     42 #include <binder/IServiceManager.h>
     43 #include <binder/MemoryHeapBase.h>
     44 #include <binder/MemoryBase.h>
     45 #include <gui/Surface.h>
     46 #include <utils/Errors.h>  // for status_t
     47 #include <utils/List.h>
     48 #include <utils/String8.h>
     49 #include <utils/SystemClock.h>
     50 #include <utils/Timers.h>
     51 #include <utils/Vector.h>
     52 
     53 #include <media/AudioPolicyHelper.h>
     54 #include <media/IMediaHTTPService.h>
     55 #include <media/IRemoteDisplay.h>
     56 #include <media/IRemoteDisplayClient.h>
     57 #include <media/MediaPlayerInterface.h>
     58 #include <media/mediarecorder.h>
     59 #include <media/MediaMetadataRetrieverInterface.h>
     60 #include <media/Metadata.h>
     61 #include <media/AudioTrack.h>
     62 #include <media/MemoryLeakTrackUtil.h>
     63 #include <media/stagefright/MediaCodecList.h>
     64 #include <media/stagefright/MediaErrors.h>
     65 #include <media/stagefright/Utils.h>
     66 #include <media/stagefright/foundation/ADebug.h>
     67 #include <media/stagefright/foundation/ALooperRoster.h>
     68 #include <mediautils/BatteryNotifier.h>
     69 
     70 //#include <memunreachable/memunreachable.h>
     71 #include <system/audio.h>
     72 
     73 #include <private/android_filesystem_config.h>
     74 
     75 #include "MediaAnalyticsService.h"
     76 
     77 #include "MetricsSummarizer.h"
     78 #include "MetricsSummarizerCodec.h"
     79 #include "MetricsSummarizerExtractor.h"
     80 #include "MetricsSummarizerPlayer.h"
     81 #include "MetricsSummarizerRecorder.h"
     82 
     83 
     84 namespace android {
     85 
     86     using namespace android::base;
     87     using namespace android::content::pm;
     88 
     89 
     90 
     91 // summarized records
     92 // up to 36 sets, each covering an hour -- so at least 1.5 days
     93 // (will be longer if there are hours without any media action)
     94 static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
     95 static const int kMaxRecordSets = 36;
     96 
     97 // individual records kept in memory: age or count
     98 // age: <= 36 hours (1.5 days)
     99 // count: hard limit of # records
    100 // (0 for either of these disables that threshold)
    101 static const nsecs_t kMaxRecordAgeNs =  36 * 3600 * (1000*1000*1000ll);
    102 static const int kMaxRecords    = 0;
    103 
    104 static const char *kServiceName = "media.metrics";
    105 
    106 void MediaAnalyticsService::instantiate() {
    107     defaultServiceManager()->addService(
    108             String16(kServiceName), new MediaAnalyticsService());
    109 }
    110 
    111 // handle sets of summarizers
    112 MediaAnalyticsService::SummarizerSet::SummarizerSet() {
    113     mSummarizers = new List<MetricsSummarizer *>();
    114 }
    115 
    116 MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
    117     // empty the list
    118     List<MetricsSummarizer *> *l = mSummarizers;
    119     while (l->size() > 0) {
    120         MetricsSummarizer *summarizer = *(l->begin());
    121         l->erase(l->begin());
    122         delete summarizer;
    123     }
    124 }
    125 
    126 void MediaAnalyticsService::newSummarizerSet() {
    127     ALOGD("MediaAnalyticsService::newSummarizerSet");
    128     MediaAnalyticsService::SummarizerSet *set = new MediaAnalyticsService::SummarizerSet();
    129     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    130     set->setStarted(now);
    131 
    132     set->appendSummarizer(new MetricsSummarizerExtractor("extractor"));
    133     set->appendSummarizer(new MetricsSummarizerCodec("codec"));
    134     set->appendSummarizer(new MetricsSummarizerPlayer("nuplayer"));
    135     set->appendSummarizer(new MetricsSummarizerRecorder("recorder"));
    136 
    137     // ALWAYS at the end, since it catches everything
    138     set->appendSummarizer(new MetricsSummarizer(NULL));
    139 
    140     // inject this set at the BACK of the list.
    141     mSummarizerSets->push_back(set);
    142     mCurrentSet = set;
    143 
    144     // limit the # that we have
    145     if (mMaxRecordSets > 0) {
    146         List<SummarizerSet *> *l = mSummarizerSets;
    147         while (l->size() > (size_t) mMaxRecordSets) {
    148             ALOGD("Deleting oldest record set....");
    149             MediaAnalyticsService::SummarizerSet *oset = *(l->begin());
    150             l->erase(l->begin());
    151             delete oset;
    152             mSetsDiscarded++;
    153         }
    154     }
    155 }
    156 
    157 MediaAnalyticsService::MediaAnalyticsService()
    158         : mMaxRecords(kMaxRecords),
    159           mMaxRecordAgeNs(kMaxRecordAgeNs),
    160           mMaxRecordSets(kMaxRecordSets),
    161           mNewSetInterval(kNewSetIntervalNs),
    162           mDumpProto(MediaAnalyticsItem::PROTO_V0) {
    163 
    164     ALOGD("MediaAnalyticsService created");
    165     // clear our queues
    166     mOpen = new List<MediaAnalyticsItem *>();
    167     mFinalized = new List<MediaAnalyticsItem *>();
    168 
    169     mSummarizerSets = new List<MediaAnalyticsService::SummarizerSet *>();
    170     newSummarizerSet();
    171 
    172     mItemsSubmitted = 0;
    173     mItemsFinalized = 0;
    174     mItemsDiscarded = 0;
    175     mItemsDiscardedExpire = 0;
    176     mItemsDiscardedCount = 0;
    177 
    178     mLastSessionID = 0;
    179     // recover any persistency we set up
    180     // etc
    181 }
    182 
    183 MediaAnalyticsService::~MediaAnalyticsService() {
    184         ALOGD("MediaAnalyticsService destroyed");
    185 
    186     // clean out mOpen and mFinalized
    187     while (mOpen->size() > 0) {
    188         MediaAnalyticsItem * oitem = *(mOpen->begin());
    189         mOpen->erase(mOpen->begin());
    190         delete oitem;
    191         mItemsDiscarded++;
    192         mItemsDiscardedCount++;
    193     }
    194     delete mOpen;
    195     mOpen = NULL;
    196 
    197     while (mFinalized->size() > 0) {
    198         MediaAnalyticsItem * oitem = *(mFinalized->begin());
    199         mFinalized->erase(mFinalized->begin());
    200         delete oitem;
    201         mItemsDiscarded++;
    202         mItemsDiscardedCount++;
    203     }
    204     delete mFinalized;
    205     mFinalized = NULL;
    206 
    207     // XXX: clean out the summaries
    208 }
    209 
    210 
    211 MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
    212     // generate a new sessionid
    213 
    214     Mutex::Autolock _l(mLock_ids);
    215     return (++mLastSessionID);
    216 }
    217 
    218 // caller surrenders ownership of 'item'
    219 MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) {
    220 
    221     MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid;
    222 
    223     // we control these, generally not trusting user input
    224     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    225     // round nsecs to seconds
    226     now = ((now + 500000000) / 1000000000) * 1000000000;
    227     item->setTimestamp(now);
    228     int pid = IPCThreadState::self()->getCallingPid();
    229     int uid = IPCThreadState::self()->getCallingUid();
    230 
    231     int uid_given = item->getUid();
    232     int pid_given = item->getPid();
    233 
    234     // although we do make exceptions for particular client uids
    235     // that we know we trust.
    236     //
    237     bool isTrusted = false;
    238 
    239     ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
    240 
    241     switch (uid)  {
    242         case AID_MEDIA:
    243         case AID_MEDIA_CODEC:
    244         case AID_MEDIA_EX:
    245         case AID_MEDIA_DRM:
    246             // trusted source, only override default values
    247             isTrusted = true;
    248             if (uid_given == (-1)) {
    249                 item->setUid(uid);
    250             }
    251             if (pid_given == (-1)) {
    252                 item->setPid(pid);
    253             }
    254             break;
    255         default:
    256             isTrusted = false;
    257             item->setPid(pid);
    258             item->setUid(uid);
    259             break;
    260     }
    261 
    262 
    263     // Overwrite package name and version if the caller was untrusted.
    264     if (!isTrusted) {
    265       setPkgInfo(item, item->getUid(), true, true);
    266     } else if (item->getPkgName().empty()) {
    267       // empty, so fill out both parts
    268       setPkgInfo(item, item->getUid(), true, true);
    269     } else {
    270       // trusted, provided a package, do nothing
    271     }
    272 
    273     ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
    274           "sanitized pkg version: %d",
    275           uid_given, item->getUid(),
    276           item->getPkgName().c_str(),
    277           item->getPkgVersionCode());
    278 
    279     mItemsSubmitted++;
    280 
    281     // validate the record; we discard if we don't like it
    282     if (contentValid(item, isTrusted) == false) {
    283         delete item;
    284         return MediaAnalyticsItem::SessionIDInvalid;
    285     }
    286 
    287 
    288     // if we have a sesisonid in the new record, look to make
    289     // sure it doesn't appear in the finalized list.
    290     // XXX: this is for security / DOS prevention.
    291     // may also require that we persist the unique sessionIDs
    292     // across boots [instead of within a single boot]
    293 
    294 
    295     // match this new record up against records in the open
    296     // list...
    297     // if there's a match, merge them together
    298     // deal with moving the old / merged record into the finalized que
    299 
    300     bool finalizing = item->getFinalized();
    301 
    302     // if finalizing, we'll remove it
    303     MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
    304     if (oitem != NULL) {
    305         if (forcenew) {
    306             // old one gets finalized, then we insert the new one
    307             // so we'll have 2 records at the end of this.
    308             // but don't finalize an empty record
    309             if (oitem->count() == 0) {
    310                 // we're responsible for disposing of the dead record
    311                 delete oitem;
    312                 oitem = NULL;
    313             } else {
    314                 oitem->setFinalized(true);
    315                 summarize(oitem);
    316                 saveItem(mFinalized, oitem, 0);
    317             }
    318             // new record could itself be marked finalized...
    319             if (finalizing) {
    320                 summarize(item);
    321                 saveItem(mFinalized, item, 0);
    322                 mItemsFinalized++;
    323             } else {
    324                 saveItem(mOpen, item, 1);
    325             }
    326             id = item->getSessionID();
    327         } else {
    328             // combine the records, send it to finalized if appropriate
    329             oitem->merge(item);
    330             if (finalizing) {
    331                 summarize(oitem);
    332                 saveItem(mFinalized, oitem, 0);
    333                 mItemsFinalized++;
    334             }
    335             id = oitem->getSessionID();
    336 
    337             // we're responsible for disposing of the dead record
    338             delete item;
    339             item = NULL;
    340         }
    341     } else {
    342         // nothing to merge, save the new record
    343         id = item->getSessionID();
    344         if (finalizing) {
    345             if (item->count() == 0) {
    346                 // drop empty records
    347                 delete item;
    348                 item = NULL;
    349             } else {
    350                 summarize(item);
    351                 saveItem(mFinalized, item, 0);
    352                 mItemsFinalized++;
    353             }
    354         } else {
    355             saveItem(mOpen, item, 1);
    356         }
    357     }
    358     return id;
    359 }
    360 
    361 
    362 status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
    363 {
    364     const size_t SIZE = 512;
    365     char buffer[SIZE];
    366     String8 result;
    367 
    368     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
    369         snprintf(buffer, SIZE, "Permission Denial: "
    370                 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
    371                 IPCThreadState::self()->getCallingPid(),
    372                 IPCThreadState::self()->getCallingUid());
    373         result.append(buffer);
    374         write(fd, result.string(), result.size());
    375         return NO_ERROR;
    376     }
    377 
    378     // crack any parameters
    379     String16 summaryOption("-summary");
    380     bool summary = false;
    381     String16 protoOption("-proto");
    382     String16 clearOption("-clear");
    383     bool clear = false;
    384     String16 sinceOption("-since");
    385     nsecs_t ts_since = 0;
    386     String16 helpOption("-help");
    387     String16 onlyOption("-only");
    388     AString only;
    389     int n = args.size();
    390 
    391     for (int i = 0; i < n; i++) {
    392         String8 myarg(args[i]);
    393         if (args[i] == clearOption) {
    394             clear = true;
    395         } else if (args[i] == summaryOption) {
    396             summary = true;
    397         } else if (args[i] == protoOption) {
    398             i++;
    399             if (i < n) {
    400                 String8 value(args[i]);
    401                 int proto = MediaAnalyticsItem::PROTO_V0;       // default to original
    402                 char *endp;
    403                 const char *p = value.string();
    404                 proto = strtol(p, &endp, 10);
    405                 if (endp != p || *endp == '\0') {
    406                     if (proto < MediaAnalyticsItem::PROTO_FIRST) {
    407                         proto = MediaAnalyticsItem::PROTO_FIRST;
    408                     } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
    409                         proto = MediaAnalyticsItem::PROTO_LAST;
    410                     }
    411                     mDumpProto = proto;
    412                 }
    413             }
    414         } else if (args[i] == sinceOption) {
    415             i++;
    416             if (i < n) {
    417                 String8 value(args[i]);
    418                 char *endp;
    419                 const char *p = value.string();
    420                 ts_since = strtoll(p, &endp, 10);
    421                 if (endp == p || *endp != '\0') {
    422                     ts_since = 0;
    423                 }
    424             } else {
    425                 ts_since = 0;
    426             }
    427             // command line is milliseconds; internal units are nano-seconds
    428             ts_since *= 1000*1000;
    429         } else if (args[i] == onlyOption) {
    430             i++;
    431             if (i < n) {
    432                 String8 value(args[i]);
    433                 only = value.string();
    434             }
    435         } else if (args[i] == helpOption) {
    436             result.append("Recognized parameters:\n");
    437             result.append("-help        this help message\n");
    438             result.append("-proto X     dump using protocol X (defaults to 1)");
    439             result.append("-summary     show summary info\n");
    440             result.append("-clear       clears out saved records\n");
    441             result.append("-only X      process records for component X\n");
    442             result.append("-since X     include records since X\n");
    443             result.append("             (X is milliseconds since the UNIX epoch)\n");
    444             write(fd, result.string(), result.size());
    445             return NO_ERROR;
    446         }
    447     }
    448 
    449     Mutex::Autolock _l(mLock);
    450 
    451     // we ALWAYS dump this piece
    452     snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
    453     result.append(buffer);
    454 
    455     dumpHeaders(result, ts_since);
    456 
    457     // want exactly 1, to avoid confusing folks that parse the output
    458     if (summary) {
    459         dumpSummaries(result, ts_since, only.c_str());
    460     } else {
    461         dumpRecent(result, ts_since, only.c_str());
    462     }
    463 
    464 
    465     if (clear) {
    466         // remove everything from the finalized queue
    467         while (mFinalized->size() > 0) {
    468             MediaAnalyticsItem * oitem = *(mFinalized->begin());
    469             mFinalized->erase(mFinalized->begin());
    470             delete oitem;
    471             mItemsDiscarded++;
    472         }
    473 
    474         // shall we clear the summary data too?
    475 
    476     }
    477 
    478     write(fd, result.string(), result.size());
    479     return NO_ERROR;
    480 }
    481 
    482 // dump headers
    483 void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
    484     const size_t SIZE = 512;
    485     char buffer[SIZE];
    486 
    487     snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
    488     result.append(buffer);
    489 
    490     int enabled = MediaAnalyticsItem::isEnabled();
    491     if (enabled) {
    492         snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
    493     } else {
    494         snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
    495     }
    496     result.append(buffer);
    497 
    498     snprintf(buffer, SIZE,
    499         "Since Boot: Submissions: %8" PRId64
    500             " Finalizations: %8" PRId64 "\n",
    501         mItemsSubmitted, mItemsFinalized);
    502     result.append(buffer);
    503     snprintf(buffer, SIZE,
    504         "Records Discarded: %8" PRId64
    505             " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
    506          mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
    507     result.append(buffer);
    508     snprintf(buffer, SIZE,
    509         "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
    510     result.append(buffer);
    511     if (ts_since != 0) {
    512         snprintf(buffer, SIZE,
    513             "Dumping Queue entries more recent than: %" PRId64 "\n",
    514             (int64_t) ts_since);
    515         result.append(buffer);
    516     }
    517 }
    518 
    519 // dump summary info
    520 void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
    521     const size_t SIZE = 512;
    522     char buffer[SIZE];
    523     int slot = 0;
    524 
    525     snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
    526     result.append(buffer);
    527 
    528     if (only != NULL && *only == '\0') {
    529         only = NULL;
    530     }
    531 
    532     // have each of the distillers dump records
    533     if (mSummarizerSets != NULL) {
    534         List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
    535         for (; itSet != mSummarizerSets->end(); itSet++) {
    536             nsecs_t when = (*itSet)->getStarted();
    537             if (when < ts_since) {
    538                 continue;
    539             }
    540             List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
    541             List<MetricsSummarizer *>::iterator it = list->begin();
    542             for (; it != list->end(); it++) {
    543                 if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
    544                     ALOGV("Told to omit '%s'", (*it)->getKey());
    545                 }
    546                 AString distilled = (*it)->dumpSummary(slot, only);
    547                 result.append(distilled.c_str());
    548             }
    549         }
    550     }
    551 }
    552 
    553 // the recent, detailed queues
    554 void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
    555     const size_t SIZE = 512;
    556     char buffer[SIZE];
    557 
    558     if (only != NULL && *only == '\0') {
    559         only = NULL;
    560     }
    561 
    562     // show the recently recorded records
    563     snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
    564     result.append(buffer);
    565     result.append(this->dumpQueue(mFinalized, ts_since, only));
    566 
    567     snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
    568     result.append(buffer);
    569     result.append(this->dumpQueue(mOpen, ts_since, only));
    570 
    571     // show who is connected and injecting records?
    572     // talk about # records fed to the 'readers'
    573     // talk about # records we discarded, perhaps "discarded w/o reading" too
    574 }
    575 // caller has locked mLock...
    576 String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
    577     return dumpQueue(theList, (nsecs_t) 0, NULL);
    578 }
    579 
    580 String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
    581     String8 result;
    582     int slot = 0;
    583 
    584     if (theList->empty()) {
    585             result.append("empty\n");
    586     } else {
    587         List<MediaAnalyticsItem *>::iterator it = theList->begin();
    588         for (; it != theList->end(); it++) {
    589             nsecs_t when = (*it)->getTimestamp();
    590             if (when < ts_since) {
    591                 continue;
    592             }
    593             if (only != NULL &&
    594                 strcmp(only, (*it)->getKey().c_str()) != 0) {
    595                 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
    596                 continue;
    597             }
    598             AString entry = (*it)->toString(mDumpProto);
    599             result.appendFormat("%5d: %s\n", slot, entry.c_str());
    600             slot++;
    601         }
    602     }
    603 
    604     return result;
    605 }
    606 
    607 //
    608 // Our Cheap in-core, non-persistent records management.
    609 // XXX: rewrite this to manage persistence, etc.
    610 
    611 // insert appropriately into queue
    612 void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
    613 
    614     Mutex::Autolock _l(mLock);
    615 
    616     // adding at back of queue (fifo order)
    617     if (front)  {
    618         l->push_front(item);
    619     } else {
    620         l->push_back(item);
    621     }
    622 
    623     // keep removing old records the front until we're in-bounds (count)
    624     if (mMaxRecords > 0) {
    625         while (l->size() > (size_t) mMaxRecords) {
    626             MediaAnalyticsItem * oitem = *(l->begin());
    627             l->erase(l->begin());
    628             delete oitem;
    629             mItemsDiscarded++;
    630             mItemsDiscardedCount++;
    631         }
    632     }
    633 
    634     // keep removing old records the front until we're in-bounds (count)
    635     if (mMaxRecordAgeNs > 0) {
    636         nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    637         while (l->size() > 0) {
    638             MediaAnalyticsItem * oitem = *(l->begin());
    639             nsecs_t when = oitem->getTimestamp();
    640             // careful about timejumps too
    641             if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
    642                 // this (and the rest) are recent enough to keep
    643                 break;
    644             }
    645             l->erase(l->begin());
    646             delete oitem;
    647             mItemsDiscarded++;
    648             mItemsDiscardedExpire++;
    649         }
    650     }
    651 }
    652 
    653 // are they alike enough that nitem can be folded into oitem?
    654 static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
    655 
    656     // general safety
    657     if (nitem->getUid() != oitem->getUid()) {
    658         return false;
    659     }
    660     if (nitem->getPid() != oitem->getPid()) {
    661         return false;
    662     }
    663 
    664     // key -- needs to match
    665     if (nitem->getKey() == oitem->getKey()) {
    666         // still in the game.
    667     } else {
    668         return false;
    669     }
    670 
    671     // session id -- empty field in new is allowed
    672     MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
    673     MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
    674     if (nsession != osession) {
    675         // incoming '0' matches value in osession
    676         if (nsession != 0) {
    677             return false;
    678         }
    679     }
    680 
    681     return true;
    682 }
    683 
    684 // find the incomplete record that this will overlay
    685 MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
    686     if (nitem == NULL) {
    687         return NULL;
    688     }
    689 
    690     MediaAnalyticsItem *item = NULL;
    691 
    692     Mutex::Autolock _l(mLock);
    693 
    694     for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
    695         it != theList->end(); it++) {
    696         MediaAnalyticsItem *tmp = (*it);
    697 
    698         if (!compatibleItems(tmp, nitem)) {
    699             continue;
    700         }
    701 
    702         // we match! this is the one I want.
    703         if (removeit) {
    704             theList->erase(it);
    705         }
    706         item = tmp;
    707         break;
    708     }
    709     return item;
    710 }
    711 
    712 
    713 // delete the indicated record
    714 void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
    715 
    716     Mutex::Autolock _l(mLock);
    717 
    718     for (List<MediaAnalyticsItem *>::iterator it = l->begin();
    719         it != l->end(); it++) {
    720         if ((*it)->getSessionID() != item->getSessionID())
    721             continue;
    722         delete *it;
    723         l->erase(it);
    724         break;
    725     }
    726 }
    727 
    728 static AString allowedKeys[] =
    729 {
    730     "codec",
    731     "extractor"
    732 };
    733 
    734 static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
    735 
    736 // are the contents good
    737 bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
    738 
    739     // untrusted uids can only send us a limited set of keys
    740     if (isTrusted == false) {
    741         // restrict to a specific set of keys
    742         AString key = item->getKey();
    743 
    744         size_t i;
    745         for(i = 0; i < nAllowedKeys; i++) {
    746             if (key == allowedKeys[i]) {
    747                 break;
    748             }
    749         }
    750         if (i == nAllowedKeys) {
    751             ALOGD("Ignoring (key): %s", item->toString().c_str());
    752             return false;
    753         }
    754     }
    755 
    756     // internal consistency
    757 
    758     return true;
    759 }
    760 
    761 // are we rate limited, normally false
    762 bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
    763 
    764     return false;
    765 }
    766 
    767 // insert into the appropriate summarizer.
    768 // we make our own copy to save/summarize
    769 void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {
    770 
    771     ALOGV("MediaAnalyticsService::summarize()");
    772 
    773     if (item == NULL) {
    774         return;
    775     }
    776 
    777     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    778     if (mCurrentSet == NULL
    779         || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
    780         newSummarizerSet();
    781     }
    782 
    783     if (mCurrentSet == NULL) {
    784         return;
    785     }
    786 
    787     List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
    788     List<MetricsSummarizer *>::iterator it = summarizers->begin();
    789     for (; it != summarizers->end(); it++) {
    790         if ((*it)->isMine(*item)) {
    791             break;
    792         }
    793     }
    794     if (it == summarizers->end()) {
    795         ALOGD("no handler for type %s", item->getKey().c_str());
    796         return;               // no handler
    797     }
    798 
    799     // invoke the summarizer. summarizer will make whatever copies
    800     // it wants; the caller retains ownership of item.
    801 
    802     (*it)->handleRecord(item);
    803 
    804 }
    805 
    806 // how long we hold package info before we re-fetch it
    807 #define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
    808 
    809 // give me the package name, perhaps going to find it
    810 void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
    811     ALOGV("asking for packagename to go with uid=%d", uid);
    812 
    813     if (!setName && !setVersion) {
    814         // setting nothing? strange
    815         return;
    816     }
    817 
    818     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    819     struct UidToPkgMap mapping;
    820     mapping.uid = (-1);
    821 
    822     ssize_t i = mPkgMappings.indexOfKey(uid);
    823     if (i >= 0) {
    824         mapping = mPkgMappings.valueAt(i);
    825         ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
    826               uid, mapping.expiration, now);
    827         if (mapping.expiration < now) {
    828             // purge our current entry and re-query
    829             ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
    830             mPkgMappings.removeItemsAt(i, 1);
    831             // could cheat and use a goto back to the top of the routine.
    832             // a good compiler should recognize the local tail recursion...
    833             return setPkgInfo(item, uid, setName, setVersion);
    834         }
    835     } else {
    836         AString pkg;
    837         std::string installer = "";
    838         int32_t versionCode = 0;
    839 
    840         struct passwd *pw = getpwuid(uid);
    841         if (pw) {
    842             pkg = pw->pw_name;
    843         }
    844 
    845         // find the proper value -- should we cache this binder??
    846 
    847         sp<IBinder> binder = NULL;
    848         sp<IServiceManager> sm = defaultServiceManager();
    849         if (sm == NULL) {
    850             ALOGE("defaultServiceManager failed");
    851         } else {
    852             binder = sm->getService(String16("package_native"));
    853             if (binder == NULL) {
    854                 ALOGE("getService package_native failed");
    855             }
    856         }
    857 
    858         if (binder != NULL) {
    859             sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
    860             binder::Status status;
    861 
    862             std::vector<int> uids;
    863             std::vector<std::string> names;
    864 
    865             uids.push_back(uid);
    866 
    867             status = package_mgr->getNamesForUids(uids, &names);
    868             if (!status.isOk()) {
    869                 ALOGE("package_native::getNamesForUids failed: %s",
    870                       status.exceptionMessage().c_str());
    871             } else {
    872                 if (!names[0].empty()) {
    873                     pkg = names[0].c_str();
    874                 }
    875             }
    876 
    877             // strip any leading "shared:" strings that came back
    878             if (pkg.startsWith("shared:")) {
    879                 pkg.erase(0, 7);
    880             }
    881 
    882             // determine how pkg was installed and the versionCode
    883             //
    884             if (pkg.empty()) {
    885                 // no name for us to manage
    886             } else if (strchr(pkg.c_str(), '.') == NULL) {
    887                 // not of form 'com.whatever...'; assume internal and ok
    888             } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
    889                 // android.* packages are assumed fine
    890             } else {
    891                 String16 pkgName16(pkg.c_str());
    892                 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
    893                 if (!status.isOk()) {
    894                     ALOGE("package_native::getInstallerForPackage failed: %s",
    895                           status.exceptionMessage().c_str());
    896                 }
    897 
    898                 // skip if we didn't get an installer
    899                 if (status.isOk()) {
    900                     status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
    901                     if (!status.isOk()) {
    902                         ALOGE("package_native::getVersionCodeForPackage failed: %s",
    903                           status.exceptionMessage().c_str());
    904                     }
    905                 }
    906 
    907 
    908                 ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
    909                       pkg.c_str(), installer.c_str(), versionCode, versionCode);
    910 
    911                 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
    912                         // from play store, we keep info
    913                 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
    914                         // some google source, we keep info
    915                 } else if (strcmp(installer.c_str(), "preload") == 0) {
    916                         // preloads, we keep the info
    917                 } else if (installer.c_str()[0] == '\0') {
    918                         // sideload (no installer); do not report
    919                         pkg = "";
    920                         versionCode = 0;
    921                 } else {
    922                         // unknown installer; do not report
    923                         pkg = "";
    924                         versionCode = 0;
    925                 }
    926             }
    927         }
    928 
    929         // add it to the map, to save a subsequent lookup
    930         if (!pkg.empty()) {
    931             Mutex::Autolock _l(mLock_mappings);
    932             ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
    933             ssize_t i = mPkgMappings.indexOfKey(uid);
    934             if (i < 0) {
    935                 mapping.uid = uid;
    936                 mapping.pkg = pkg;
    937                 mapping.installer = installer.c_str();
    938                 mapping.versionCode = versionCode;
    939                 mapping.expiration = now + PKG_EXPIRATION_NS;
    940                 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
    941 
    942                 mPkgMappings.add(uid, mapping);
    943             }
    944         }
    945     }
    946 
    947     if (mapping.uid != (uid_t)(-1)) {
    948         if (setName) {
    949             item->setPkgName(mapping.pkg);
    950         }
    951         if (setVersion) {
    952             item->setPkgVersionCode(mapping.versionCode);
    953         }
    954     }
    955 }
    956 
    957 } // namespace android
    958