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