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 <pthread.h>
     30 #include <unistd.h>
     31 
     32 #include <string.h>
     33 #include <pwd.h>
     34 
     35 #include <cutils/atomic.h>
     36 #include <cutils/properties.h> // for property_get
     37 
     38 #include <utils/misc.h>
     39 
     40 #include <android/content/pm/IPackageManagerNative.h>
     41 
     42 #include <binder/IPCThreadState.h>
     43 #include <binder/IServiceManager.h>
     44 #include <binder/MemoryHeapBase.h>
     45 #include <binder/MemoryBase.h>
     46 #include <gui/Surface.h>
     47 #include <utils/Errors.h>  // for status_t
     48 #include <utils/List.h>
     49 #include <utils/String8.h>
     50 #include <utils/SystemClock.h>
     51 #include <utils/Timers.h>
     52 #include <utils/Vector.h>
     53 
     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 namespace android {
     78 
     79 // individual records kept in memory: age or count
     80 // age: <= 28 hours (1 1/6 days)
     81 // count: hard limit of # records
     82 // (0 for either of these disables that threshold)
     83 //
     84 static constexpr nsecs_t kMaxRecordAgeNs =  28 * 3600 * (1000*1000*1000ll);
     85 // 2019/6: average daily per device is currently 375-ish;
     86 // setting this to 2000 is large enough to catch most devices
     87 // we'll lose some data on very very media-active devices, but only for
     88 // the gms collection; statsd will have already covered those for us.
     89 // This also retains enough information to help with bugreports
     90 static constexpr int kMaxRecords    = 2000;
     91 
     92 // max we expire in a single call, to constrain how long we hold the
     93 // mutex, which also constrains how long a client might wait.
     94 static constexpr int kMaxExpiredAtOnce = 50;
     95 
     96 // TODO: need to look at tuning kMaxRecords and friends for low-memory devices
     97 
     98 static const char *kServiceName = "media.metrics";
     99 
    100 void MediaAnalyticsService::instantiate() {
    101     defaultServiceManager()->addService(
    102             String16(kServiceName), new MediaAnalyticsService());
    103 }
    104 
    105 MediaAnalyticsService::MediaAnalyticsService()
    106         : mMaxRecords(kMaxRecords),
    107           mMaxRecordAgeNs(kMaxRecordAgeNs),
    108           mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
    109           mDumpProto(MediaAnalyticsItem::PROTO_V1),
    110           mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
    111 
    112     ALOGD("MediaAnalyticsService created");
    113 
    114     mItemsSubmitted = 0;
    115     mItemsFinalized = 0;
    116     mItemsDiscarded = 0;
    117     mItemsDiscardedExpire = 0;
    118     mItemsDiscardedCount = 0;
    119 
    120     mLastSessionID = 0;
    121     // recover any persistency we set up
    122     // etc
    123 }
    124 
    125 MediaAnalyticsService::~MediaAnalyticsService() {
    126         ALOGD("MediaAnalyticsService destroyed");
    127 
    128     while (mItems.size() > 0) {
    129         MediaAnalyticsItem * oitem = *(mItems.begin());
    130         mItems.erase(mItems.begin());
    131         delete oitem;
    132         mItemsDiscarded++;
    133         mItemsDiscardedCount++;
    134     }
    135 }
    136 
    137 
    138 MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
    139     // generate a new sessionid
    140 
    141     Mutex::Autolock _l(mLock_ids);
    142     return (++mLastSessionID);
    143 }
    144 
    145 // caller surrenders ownership of 'item'
    146 MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
    147 {
    148     UNUSED(forcenew);
    149 
    150     // fill in a sessionID if we do not yet have one
    151     if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
    152         item->setSessionID(generateUniqueSessionID());
    153     }
    154 
    155     // we control these, generally not trusting user input
    156     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    157     // round nsecs to seconds
    158     now = ((now + 500000000) / 1000000000) * 1000000000;
    159     item->setTimestamp(now);
    160     int pid = IPCThreadState::self()->getCallingPid();
    161     int uid = IPCThreadState::self()->getCallingUid();
    162 
    163     int uid_given = item->getUid();
    164     int pid_given = item->getPid();
    165 
    166     // although we do make exceptions for some trusted client uids
    167     bool isTrusted = false;
    168 
    169     ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
    170 
    171     switch (uid)  {
    172         case AID_MEDIA:
    173         case AID_MEDIA_CODEC:
    174         case AID_MEDIA_EX:
    175         case AID_MEDIA_DRM:
    176             // trusted source, only override default values
    177             isTrusted = true;
    178             if (uid_given == (-1)) {
    179                 item->setUid(uid);
    180             }
    181             if (pid_given == (-1)) {
    182                 item->setPid(pid);
    183             }
    184             break;
    185         default:
    186             isTrusted = false;
    187             item->setPid(pid);
    188             item->setUid(uid);
    189             break;
    190     }
    191 
    192     // Overwrite package name and version if the caller was untrusted.
    193     if (!isTrusted) {
    194       setPkgInfo(item, item->getUid(), true, true);
    195     } else if (item->getPkgName().empty()) {
    196       // empty, so fill out both parts
    197       setPkgInfo(item, item->getUid(), true, true);
    198     } else {
    199       // trusted, provided a package, do nothing
    200     }
    201 
    202     ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
    203           "sanitized pkg version: %"  PRId64,
    204           uid_given, item->getUid(),
    205           item->getPkgName().c_str(),
    206           item->getPkgVersionCode());
    207 
    208     mItemsSubmitted++;
    209 
    210     // validate the record; we discard if we don't like it
    211     if (contentValid(item, isTrusted) == false) {
    212         delete item;
    213         return MediaAnalyticsItem::SessionIDInvalid;
    214     }
    215 
    216     // XXX: if we have a sessionid in the new record, look to make
    217     // sure it doesn't appear in the finalized list.
    218 
    219     if (item->count() == 0) {
    220         ALOGV("dropping empty record...");
    221         delete item;
    222         item = NULL;
    223         return MediaAnalyticsItem::SessionIDInvalid;
    224     }
    225 
    226     // save the new record
    227     //
    228     // send a copy to statsd
    229     dump2Statsd(item);
    230 
    231     // and keep our copy for dumpsys
    232     MediaAnalyticsItem::SessionID_t id = item->getSessionID();
    233     saveItem(item);
    234     mItemsFinalized++;
    235 
    236     return id;
    237 }
    238 
    239 
    240 status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
    241 {
    242     const size_t SIZE = 512;
    243     char buffer[SIZE];
    244     String8 result;
    245 
    246     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
    247         snprintf(buffer, SIZE, "Permission Denial: "
    248                 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
    249                 IPCThreadState::self()->getCallingPid(),
    250                 IPCThreadState::self()->getCallingUid());
    251         result.append(buffer);
    252         write(fd, result.string(), result.size());
    253         return NO_ERROR;
    254     }
    255 
    256     // crack any parameters
    257     String16 protoOption("-proto");
    258     int chosenProto = mDumpProtoDefault;
    259     String16 clearOption("-clear");
    260     bool clear = false;
    261     String16 sinceOption("-since");
    262     nsecs_t ts_since = 0;
    263     String16 helpOption("-help");
    264     String16 onlyOption("-only");
    265     std::string only;
    266     int n = args.size();
    267 
    268     for (int i = 0; i < n; i++) {
    269         String8 myarg(args[i]);
    270         if (args[i] == clearOption) {
    271             clear = true;
    272         } else if (args[i] == protoOption) {
    273             i++;
    274             if (i < n) {
    275                 String8 value(args[i]);
    276                 int proto = MediaAnalyticsItem::PROTO_V0;
    277                 char *endp;
    278                 const char *p = value.string();
    279                 proto = strtol(p, &endp, 10);
    280                 if (endp != p || *endp == '\0') {
    281                     if (proto < MediaAnalyticsItem::PROTO_FIRST) {
    282                         proto = MediaAnalyticsItem::PROTO_FIRST;
    283                     } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
    284                         proto = MediaAnalyticsItem::PROTO_LAST;
    285                     }
    286                     chosenProto = proto;
    287                 } else {
    288                     result.append("unable to parse value for -proto\n\n");
    289                 }
    290             } else {
    291                 result.append("missing value for -proto\n\n");
    292             }
    293         } else if (args[i] == sinceOption) {
    294             i++;
    295             if (i < n) {
    296                 String8 value(args[i]);
    297                 char *endp;
    298                 const char *p = value.string();
    299                 ts_since = strtoll(p, &endp, 10);
    300                 if (endp == p || *endp != '\0') {
    301                     ts_since = 0;
    302                 }
    303             } else {
    304                 ts_since = 0;
    305             }
    306             // command line is milliseconds; internal units are nano-seconds
    307             ts_since *= 1000*1000;
    308         } else if (args[i] == onlyOption) {
    309             i++;
    310             if (i < n) {
    311                 String8 value(args[i]);
    312                 only = value.string();
    313             }
    314         } else if (args[i] == helpOption) {
    315             result.append("Recognized parameters:\n");
    316             result.append("-help        this help message\n");
    317             result.append("-proto #     dump using protocol #");
    318             result.append("-clear       clears out saved records\n");
    319             result.append("-only X      process records for component X\n");
    320             result.append("-since X     include records since X\n");
    321             result.append("             (X is milliseconds since the UNIX epoch)\n");
    322             write(fd, result.string(), result.size());
    323             return NO_ERROR;
    324         }
    325     }
    326 
    327     Mutex::Autolock _l(mLock);
    328     // mutex between insertion and dumping the contents
    329 
    330     mDumpProto = chosenProto;
    331 
    332     // we ALWAYS dump this piece
    333     snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
    334     result.append(buffer);
    335 
    336     dumpHeaders(result, ts_since);
    337 
    338     dumpRecent(result, ts_since, only.c_str());
    339 
    340 
    341     if (clear) {
    342         // remove everything from the finalized queue
    343         while (mItems.size() > 0) {
    344             MediaAnalyticsItem * oitem = *(mItems.begin());
    345             mItems.erase(mItems.begin());
    346             delete oitem;
    347             mItemsDiscarded++;
    348         }
    349 
    350         // shall we clear the summary data too?
    351 
    352     }
    353 
    354     write(fd, result.string(), result.size());
    355     return NO_ERROR;
    356 }
    357 
    358 // dump headers
    359 void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
    360 {
    361     const size_t SIZE = 512;
    362     char buffer[SIZE];
    363 
    364     snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
    365     result.append(buffer);
    366 
    367     int enabled = MediaAnalyticsItem::isEnabled();
    368     if (enabled) {
    369         snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
    370     } else {
    371         snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
    372     }
    373     result.append(buffer);
    374 
    375     snprintf(buffer, SIZE,
    376         "Since Boot: Submissions: %8" PRId64
    377             " Accepted: %8" PRId64 "\n",
    378         mItemsSubmitted, mItemsFinalized);
    379     result.append(buffer);
    380     snprintf(buffer, SIZE,
    381         "Records Discarded: %8" PRId64
    382             " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
    383          mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
    384     result.append(buffer);
    385     if (ts_since != 0) {
    386         snprintf(buffer, SIZE,
    387             "Emitting Queue entries more recent than: %" PRId64 "\n",
    388             (int64_t) ts_since);
    389         result.append(buffer);
    390     }
    391 }
    392 
    393 // the recent, detailed queues
    394 void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
    395 {
    396     const size_t SIZE = 512;
    397     char buffer[SIZE];
    398 
    399     if (only != NULL && *only == '\0') {
    400         only = NULL;
    401     }
    402 
    403     // show the recently recorded records
    404     snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
    405     result.append(buffer);
    406     result.append(this->dumpQueue(ts_since, only));
    407 
    408     // show who is connected and injecting records?
    409     // talk about # records fed to the 'readers'
    410     // talk about # records we discarded, perhaps "discarded w/o reading" too
    411 }
    412 
    413 // caller has locked mLock...
    414 String8 MediaAnalyticsService::dumpQueue() {
    415     return dumpQueue((nsecs_t) 0, NULL);
    416 }
    417 
    418 String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
    419     String8 result;
    420     int slot = 0;
    421 
    422     if (mItems.empty()) {
    423             result.append("empty\n");
    424     } else {
    425         List<MediaAnalyticsItem *>::iterator it = mItems.begin();
    426         for (; it != mItems.end(); it++) {
    427             nsecs_t when = (*it)->getTimestamp();
    428             if (when < ts_since) {
    429                 continue;
    430             }
    431             if (only != NULL &&
    432                 strcmp(only, (*it)->getKey().c_str()) != 0) {
    433                 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
    434                 continue;
    435             }
    436             std::string entry = (*it)->toString(mDumpProto);
    437             result.appendFormat("%5d: %s\n", slot, entry.c_str());
    438             slot++;
    439         }
    440     }
    441 
    442     return result;
    443 }
    444 
    445 //
    446 // Our Cheap in-core, non-persistent records management.
    447 
    448 
    449 // we hold mLock when we get here
    450 // if item != NULL, it's the item we just inserted
    451 // true == more items eligible to be recovered
    452 bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
    453 {
    454     bool more = false;
    455     int handled = 0;
    456 
    457     // keep removing old records the front until we're in-bounds (count)
    458     // since we invoke this with each insertion, it should be 0/1 iterations.
    459     if (mMaxRecords > 0) {
    460         while (mItems.size() > (size_t) mMaxRecords) {
    461             MediaAnalyticsItem * oitem = *(mItems.begin());
    462             if (oitem == item) {
    463                 break;
    464             }
    465             if (handled >= mMaxRecordsExpiredAtOnce) {
    466                 // unlikely in this loop
    467                 more = true;
    468                 break;
    469             }
    470             handled++;
    471             mItems.erase(mItems.begin());
    472             delete oitem;
    473             mItemsDiscarded++;
    474             mItemsDiscardedCount++;
    475         }
    476     }
    477 
    478     // keep removing old records the front until we're in-bounds (age)
    479     // limited to mMaxRecordsExpiredAtOnce items per invocation.
    480     if (mMaxRecordAgeNs > 0) {
    481         nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    482         while (mItems.size() > 0) {
    483             MediaAnalyticsItem * oitem = *(mItems.begin());
    484             nsecs_t when = oitem->getTimestamp();
    485             if (oitem == item) {
    486                 break;
    487             }
    488             // careful about timejumps too
    489             if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
    490                 // this (and the rest) are recent enough to keep
    491                 break;
    492             }
    493             if (handled >= mMaxRecordsExpiredAtOnce) {
    494                 // this represents "one too many"; tell caller there are
    495                 // more to be reclaimed.
    496                 more = true;
    497                 break;
    498             }
    499             handled++;
    500             mItems.erase(mItems.begin());
    501             delete oitem;
    502             mItemsDiscarded++;
    503             mItemsDiscardedExpire++;
    504         }
    505     }
    506 
    507     // we only indicate whether there's more to clean;
    508     // caller chooses whether to schedule further cleanup.
    509     return more;
    510 }
    511 
    512 // process expirations in bite sized chunks, allowing new insertions through
    513 // runs in a pthread specifically started for this (which then exits)
    514 bool MediaAnalyticsService::processExpirations()
    515 {
    516     bool more;
    517     do {
    518         sleep(1);
    519         {
    520             Mutex::Autolock _l(mLock);
    521             more = expirations_l(NULL);
    522             if (!more) {
    523                 break;
    524             }
    525         }
    526     } while (more);
    527     return true;        // value is for std::future thread synchronization
    528 }
    529 
    530 // insert appropriately into queue
    531 void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
    532 {
    533 
    534     Mutex::Autolock _l(mLock);
    535     // mutex between insertion and dumping the contents
    536 
    537     // we want to dump 'in FIFO order', so insert at the end
    538     mItems.push_back(item);
    539 
    540     // clean old stuff from the queue
    541     bool more = expirations_l(item);
    542 
    543     // consider scheduling some asynchronous cleaning, if not running
    544     if (more) {
    545         if (!mExpireFuture.valid()
    546             || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
    547 
    548             mExpireFuture = std::async(std::launch::async, [this]()
    549                                        {return this->processExpirations();});
    550         }
    551     }
    552 }
    553 
    554 static std::string allowedKeys[] =
    555 {
    556     "audiopolicy",
    557     "audiorecord",
    558     "audiothread",
    559     "audiotrack",
    560     "codec",
    561     "extractor",
    562     "nuplayer",
    563 };
    564 
    565 static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
    566 
    567 // are the contents good
    568 bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
    569 
    570     // untrusted uids can only send us a limited set of keys
    571     if (isTrusted == false) {
    572         // restrict to a specific set of keys
    573         std::string key = item->getKey();
    574 
    575         size_t i;
    576         for(i = 0; i < nAllowedKeys; i++) {
    577             if (key == allowedKeys[i]) {
    578                 break;
    579             }
    580         }
    581         if (i == nAllowedKeys) {
    582             ALOGD("Ignoring (key): %s", item->toString().c_str());
    583             return false;
    584         }
    585     }
    586 
    587     // internal consistency
    588 
    589     return true;
    590 }
    591 
    592 // are we rate limited, normally false
    593 bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
    594 
    595     return false;
    596 }
    597 
    598 // how long we hold package info before we re-fetch it
    599 #define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
    600 
    601 // give me the package name, perhaps going to find it
    602 // manages its own mutex operations internally
    603 void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
    604 {
    605     ALOGV("asking for packagename to go with uid=%d", uid);
    606 
    607     if (!setName && !setVersion) {
    608         // setting nothing? strange
    609         return;
    610     }
    611 
    612     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    613     struct UidToPkgMap mapping;
    614     mapping.uid = (uid_t)(-1);
    615 
    616     {
    617         Mutex::Autolock _l(mLock_mappings);
    618         int i = mPkgMappings.indexOfKey(uid);
    619         if (i >= 0) {
    620             mapping = mPkgMappings.valueAt(i);
    621             ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
    622                   uid, mapping.expiration, now);
    623             if (mapping.expiration <= now) {
    624                 // purge the stale entry and fall into re-fetching
    625                 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
    626                 mPkgMappings.removeItemsAt(i);
    627                 mapping.uid = (uid_t)(-1);
    628             }
    629         }
    630     }
    631 
    632     // if we did not find it
    633     if (mapping.uid == (uid_t)(-1)) {
    634         std::string pkg;
    635         std::string installer = "";
    636         int64_t versionCode = 0;
    637 
    638         struct passwd *pw = getpwuid(uid);
    639         if (pw) {
    640             pkg = pw->pw_name;
    641         }
    642 
    643         // find the proper value
    644 
    645         sp<IBinder> binder = NULL;
    646         sp<IServiceManager> sm = defaultServiceManager();
    647         if (sm == NULL) {
    648             ALOGE("defaultServiceManager failed");
    649         } else {
    650             binder = sm->getService(String16("package_native"));
    651             if (binder == NULL) {
    652                 ALOGE("getService package_native failed");
    653             }
    654         }
    655 
    656         if (binder != NULL) {
    657             sp<content::pm::IPackageManagerNative> package_mgr =
    658                             interface_cast<content::pm::IPackageManagerNative>(binder);
    659             binder::Status status;
    660 
    661             std::vector<int> uids;
    662             std::vector<std::string> names;
    663 
    664             uids.push_back(uid);
    665 
    666             status = package_mgr->getNamesForUids(uids, &names);
    667             if (!status.isOk()) {
    668                 ALOGE("package_native::getNamesForUids failed: %s",
    669                       status.exceptionMessage().c_str());
    670             } else {
    671                 if (!names[0].empty()) {
    672                     pkg = names[0].c_str();
    673                 }
    674             }
    675 
    676             // strip any leading "shared:" strings that came back
    677             if (pkg.compare(0, 7, "shared:") == 0) {
    678                 pkg.erase(0, 7);
    679             }
    680 
    681             // determine how pkg was installed and the versionCode
    682             //
    683             if (pkg.empty()) {
    684                 // no name for us to manage
    685             } else if (strchr(pkg.c_str(), '.') == NULL) {
    686                 // not of form 'com.whatever...'; assume internal and ok
    687             } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
    688                 // android.* packages are assumed fine
    689             } else {
    690                 String16 pkgName16(pkg.c_str());
    691                 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
    692                 if (!status.isOk()) {
    693                     ALOGE("package_native::getInstallerForPackage failed: %s",
    694                           status.exceptionMessage().c_str());
    695                 }
    696 
    697                 // skip if we didn't get an installer
    698                 if (status.isOk()) {
    699                     status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
    700                     if (!status.isOk()) {
    701                         ALOGE("package_native::getVersionCodeForPackage failed: %s",
    702                           status.exceptionMessage().c_str());
    703                     }
    704                 }
    705 
    706 
    707                 ALOGV("package '%s' installed by '%s' versioncode %"  PRId64 " / %" PRIx64,
    708                       pkg.c_str(), installer.c_str(), versionCode, versionCode);
    709 
    710                 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
    711                         // from play store, we keep info
    712                 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
    713                         // some google source, we keep info
    714                 } else if (strcmp(installer.c_str(), "preload") == 0) {
    715                         // preloads, we keep the info
    716                 } else if (installer.c_str()[0] == '\0') {
    717                         // sideload (no installer); do not report
    718                         pkg = "";
    719                         versionCode = 0;
    720                 } else {
    721                         // unknown installer; do not report
    722                         pkg = "";
    723                         versionCode = 0;
    724                 }
    725             }
    726         }
    727 
    728         // add it to the map, to save a subsequent lookup
    729         if (!pkg.empty()) {
    730             Mutex::Autolock _l(mLock_mappings);
    731             ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
    732             ssize_t i = mPkgMappings.indexOfKey(uid);
    733             if (i < 0) {
    734                 mapping.uid = uid;
    735                 mapping.pkg = pkg;
    736                 mapping.installer = installer.c_str();
    737                 mapping.versionCode = versionCode;
    738                 mapping.expiration = now + PKG_EXPIRATION_NS;
    739                 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
    740 
    741                 mPkgMappings.add(uid, mapping);
    742             }
    743         }
    744     }
    745 
    746     if (mapping.uid != (uid_t)(-1)) {
    747         if (setName) {
    748             item->setPkgName(mapping.pkg);
    749         }
    750         if (setVersion) {
    751             item->setPkgVersionCode(mapping.versionCode);
    752         }
    753     }
    754 }
    755 
    756 } // namespace android
    757