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 
instantiate()100 void MediaAnalyticsService::instantiate() {
101     defaultServiceManager()->addService(
102             String16(kServiceName), new MediaAnalyticsService());
103 }
104 
MediaAnalyticsService()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 
~MediaAnalyticsService()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 
generateUniqueSessionID()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'
submit(MediaAnalyticsItem * item,bool forcenew)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 
dump(int fd,const Vector<String16> & args)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
dumpHeaders(String8 & result,nsecs_t ts_since)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
dumpRecent(String8 & result,nsecs_t ts_since,const char * only)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...
dumpQueue()414 String8 MediaAnalyticsService::dumpQueue() {
415     return dumpQueue((nsecs_t) 0, NULL);
416 }
417 
dumpQueue(nsecs_t ts_since,const char * only)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
expirations_l(MediaAnalyticsItem * item)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)
processExpirations()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
saveItem(MediaAnalyticsItem * item)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
contentValid(MediaAnalyticsItem * item,bool isTrusted)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
rateLimited(MediaAnalyticsItem *)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
setPkgInfo(MediaAnalyticsItem * item,uid_t uid,bool setName,bool setVersion)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