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