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