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