1 /* 2 * Copyright (C) 2016 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 #undef LOG_TAG 18 #define LOG_TAG "MediaAnalyticsItem" 19 20 #include <inttypes.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/types.h> 24 25 #include <binder/Parcel.h> 26 #include <utils/Errors.h> 27 #include <utils/Log.h> 28 #include <utils/Mutex.h> 29 #include <utils/SortedVector.h> 30 #include <utils/threads.h> 31 32 #include <binder/IServiceManager.h> 33 #include <media/IMediaAnalyticsService.h> 34 #include <media/MediaAnalyticsItem.h> 35 #include <private/android_filesystem_config.h> 36 37 namespace android { 38 39 #define DEBUG_SERVICEACCESS 0 40 #define DEBUG_API 0 41 #define DEBUG_ALLOCATIONS 0 42 43 // after this many failed attempts, we stop trying [from this process] and just say that 44 // the service is off. 45 #define SVC_TRIES 2 46 47 // the few universal keys we have 48 const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any"; 49 const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none"; 50 51 const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled"; 52 const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled"; 53 const int MediaAnalyticsItem::EnabledProperty_default = 1; 54 55 56 // access functions for the class 57 MediaAnalyticsItem::MediaAnalyticsItem() 58 : mPid(-1), 59 mUid(-1), 60 mPkgVersionCode(0), 61 mSessionID(MediaAnalyticsItem::SessionIDNone), 62 mTimestamp(0), 63 mFinalized(1), 64 mPropCount(0), mPropSize(0), mProps(NULL) 65 { 66 mKey = MediaAnalyticsItem::kKeyNone; 67 } 68 69 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key) 70 : mPid(-1), 71 mUid(-1), 72 mPkgVersionCode(0), 73 mSessionID(MediaAnalyticsItem::SessionIDNone), 74 mTimestamp(0), 75 mFinalized(1), 76 mPropCount(0), mPropSize(0), mProps(NULL) 77 { 78 if (DEBUG_ALLOCATIONS) { 79 ALOGD("Allocate MediaAnalyticsItem @ %p", this); 80 } 81 mKey = key; 82 } 83 84 MediaAnalyticsItem::~MediaAnalyticsItem() { 85 if (DEBUG_ALLOCATIONS) { 86 ALOGD("Destroy MediaAnalyticsItem @ %p", this); 87 } 88 clear(); 89 } 90 91 void MediaAnalyticsItem::clear() { 92 93 // clean allocated storage from key 94 mKey.clear(); 95 96 // clean various major parameters 97 mSessionID = MediaAnalyticsItem::SessionIDNone; 98 99 // clean attributes 100 // contents of the attributes 101 for (size_t i = 0 ; i < mPropCount; i++ ) { 102 clearProp(&mProps[i]); 103 } 104 // the attribute records themselves 105 if (mProps != NULL) { 106 free(mProps); 107 mProps = NULL; 108 } 109 mPropSize = 0; 110 mPropCount = 0; 111 112 return; 113 } 114 115 // make a deep copy of myself 116 MediaAnalyticsItem *MediaAnalyticsItem::dup() { 117 MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey); 118 119 if (dst != NULL) { 120 // key as part of constructor 121 dst->mPid = this->mPid; 122 dst->mUid = this->mUid; 123 dst->mPkgName = this->mPkgName; 124 dst->mPkgVersionCode = this->mPkgVersionCode; 125 dst->mSessionID = this->mSessionID; 126 dst->mTimestamp = this->mTimestamp; 127 dst->mFinalized = this->mFinalized; 128 129 // properties aka attributes 130 dst->growProps(this->mPropCount); 131 for(size_t i=0;i<mPropCount;i++) { 132 copyProp(&dst->mProps[i], &this->mProps[i]); 133 } 134 dst->mPropCount = this->mPropCount; 135 } 136 137 return dst; 138 } 139 140 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) { 141 mSessionID = id; 142 return *this; 143 } 144 145 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const { 146 return mSessionID; 147 } 148 149 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() { 150 151 if (mSessionID == SessionIDNone) { 152 // get one from the server 153 MediaAnalyticsItem::SessionID_t newid = SessionIDNone; 154 sp<IMediaAnalyticsService> svc = getInstance(); 155 if (svc != NULL) { 156 newid = svc->generateUniqueSessionID(); 157 } 158 mSessionID = newid; 159 } 160 161 return mSessionID; 162 } 163 164 MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() { 165 mSessionID = MediaAnalyticsItem::SessionIDNone; 166 return *this; 167 } 168 169 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) { 170 mTimestamp = ts; 171 return *this; 172 } 173 174 nsecs_t MediaAnalyticsItem::getTimestamp() const { 175 return mTimestamp; 176 } 177 178 MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) { 179 mPid = pid; 180 return *this; 181 } 182 183 pid_t MediaAnalyticsItem::getPid() const { 184 return mPid; 185 } 186 187 MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) { 188 mUid = uid; 189 return *this; 190 } 191 192 uid_t MediaAnalyticsItem::getUid() const { 193 return mUid; 194 } 195 196 MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(const std::string &pkgName) { 197 mPkgName = pkgName; 198 return *this; 199 } 200 201 MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int64_t pkgVersionCode) { 202 mPkgVersionCode = pkgVersionCode; 203 return *this; 204 } 205 206 int64_t MediaAnalyticsItem::getPkgVersionCode() const { 207 return mPkgVersionCode; 208 } 209 210 // this key is for the overall record -- "codec", "player", "drm", etc 211 MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) { 212 mKey = key; 213 return *this; 214 } 215 216 MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() { 217 return mKey; 218 } 219 220 // number of attributes we have in this record 221 int32_t MediaAnalyticsItem::count() const { 222 return mPropCount; 223 } 224 225 // find the proper entry in the list 226 size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len) 227 { 228 size_t i = 0; 229 for (; i < mPropCount; i++) { 230 Prop *prop = &mProps[i]; 231 if (prop->mNameLen != len) { 232 continue; 233 } 234 if (memcmp(name, prop->mName, len) == 0) { 235 break; 236 } 237 } 238 return i; 239 } 240 241 MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) { 242 size_t len = strlen(name); 243 size_t i = findPropIndex(name, len); 244 if (i < mPropCount) { 245 return &mProps[i]; 246 } 247 return NULL; 248 } 249 250 void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) { 251 free((void *)mName); 252 mName = (const char *) malloc(len+1); 253 LOG_ALWAYS_FATAL_IF(mName == NULL, 254 "failed malloc() for property '%s' (len %zu)", 255 name, len); 256 memcpy ((void *)mName, name, len+1); 257 mNameLen = len; 258 } 259 260 // consider this "find-or-allocate". 261 // caller validates type and uses clearPropValue() accordingly 262 MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) { 263 size_t len = strlen(name); 264 size_t i = findPropIndex(name, len); 265 Prop *prop; 266 267 if (i < mPropCount) { 268 prop = &mProps[i]; 269 } else { 270 if (i == mPropSize) { 271 if (growProps() == false) { 272 ALOGE("failed allocation for new props"); 273 return NULL; 274 } 275 } 276 i = mPropCount++; 277 prop = &mProps[i]; 278 prop->setName(name, len); 279 } 280 281 return prop; 282 } 283 284 // used within the summarizers; return whether property existed 285 bool MediaAnalyticsItem::removeProp(const char *name) { 286 size_t len = strlen(name); 287 size_t i = findPropIndex(name, len); 288 if (i < mPropCount) { 289 Prop *prop = &mProps[i]; 290 clearProp(prop); 291 if (i != mPropCount-1) { 292 // in the middle, bring last one down to fill gap 293 copyProp(prop, &mProps[mPropCount-1]); 294 clearProp(&mProps[mPropCount-1]); 295 } 296 mPropCount--; 297 return true; 298 } 299 return false; 300 } 301 302 // set the values 303 void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) { 304 Prop *prop = allocateProp(name); 305 if (prop != NULL) { 306 clearPropValue(prop); 307 prop->mType = kTypeInt32; 308 prop->u.int32Value = value; 309 } 310 } 311 312 void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) { 313 Prop *prop = allocateProp(name); 314 if (prop != NULL) { 315 clearPropValue(prop); 316 prop->mType = kTypeInt64; 317 prop->u.int64Value = value; 318 } 319 } 320 321 void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) { 322 Prop *prop = allocateProp(name); 323 if (prop != NULL) { 324 clearPropValue(prop); 325 prop->mType = kTypeDouble; 326 prop->u.doubleValue = value; 327 } 328 } 329 330 void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) { 331 332 Prop *prop = allocateProp(name); 333 // any old value will be gone 334 if (prop != NULL) { 335 clearPropValue(prop); 336 prop->mType = kTypeCString; 337 prop->u.CStringValue = strdup(value); 338 } 339 } 340 341 void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) { 342 Prop *prop = allocateProp(name); 343 if (prop != NULL) { 344 clearPropValue(prop); 345 prop->mType = kTypeRate; 346 prop->u.rate.count = count; 347 prop->u.rate.duration = duration; 348 } 349 } 350 351 352 // find/add/set fused into a single operation 353 void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) { 354 Prop *prop = allocateProp(name); 355 if (prop == NULL) { 356 return; 357 } 358 switch (prop->mType) { 359 case kTypeInt32: 360 prop->u.int32Value += value; 361 break; 362 default: 363 clearPropValue(prop); 364 prop->mType = kTypeInt32; 365 prop->u.int32Value = value; 366 break; 367 } 368 } 369 370 void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) { 371 Prop *prop = allocateProp(name); 372 if (prop == NULL) { 373 return; 374 } 375 switch (prop->mType) { 376 case kTypeInt64: 377 prop->u.int64Value += value; 378 break; 379 default: 380 clearPropValue(prop); 381 prop->mType = kTypeInt64; 382 prop->u.int64Value = value; 383 break; 384 } 385 } 386 387 void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) { 388 Prop *prop = allocateProp(name); 389 if (prop == NULL) { 390 return; 391 } 392 switch (prop->mType) { 393 case kTypeRate: 394 prop->u.rate.count += count; 395 prop->u.rate.duration += duration; 396 break; 397 default: 398 clearPropValue(prop); 399 prop->mType = kTypeRate; 400 prop->u.rate.count = count; 401 prop->u.rate.duration = duration; 402 break; 403 } 404 } 405 406 void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) { 407 Prop *prop = allocateProp(name); 408 if (prop == NULL) { 409 return; 410 } 411 switch (prop->mType) { 412 case kTypeDouble: 413 prop->u.doubleValue += value; 414 break; 415 default: 416 clearPropValue(prop); 417 prop->mType = kTypeDouble; 418 prop->u.doubleValue = value; 419 break; 420 } 421 } 422 423 // find & extract values 424 bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) { 425 Prop *prop = findProp(name); 426 if (prop == NULL || prop->mType != kTypeInt32) { 427 return false; 428 } 429 if (value != NULL) { 430 *value = prop->u.int32Value; 431 } 432 return true; 433 } 434 435 bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) { 436 Prop *prop = findProp(name); 437 if (prop == NULL || prop->mType != kTypeInt64) { 438 return false; 439 } 440 if (value != NULL) { 441 *value = prop->u.int64Value; 442 } 443 return true; 444 } 445 446 bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) { 447 Prop *prop = findProp(name); 448 if (prop == NULL || prop->mType != kTypeRate) { 449 return false; 450 } 451 if (count != NULL) { 452 *count = prop->u.rate.count; 453 } 454 if (duration != NULL) { 455 *duration = prop->u.rate.duration; 456 } 457 if (rate != NULL) { 458 double r = 0.0; 459 if (prop->u.rate.duration != 0) { 460 r = prop->u.rate.count / (double) prop->u.rate.duration; 461 } 462 *rate = r; 463 } 464 return true; 465 } 466 467 bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) { 468 Prop *prop = findProp(name); 469 if (prop == NULL || prop->mType != kTypeDouble) { 470 return false; 471 } 472 if (value != NULL) { 473 *value = prop->u.doubleValue; 474 } 475 return true; 476 } 477 478 // caller responsible for the returned string 479 bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) { 480 Prop *prop = findProp(name); 481 if (prop == NULL || prop->mType != kTypeDouble) { 482 return false; 483 } 484 if (value != NULL) { 485 *value = strdup(prop->u.CStringValue); 486 } 487 return true; 488 } 489 490 // remove indicated keys and their values 491 // return value is # keys removed 492 int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) { 493 int zapped = 0; 494 if (attrs == NULL || n <= 0) { 495 return -1; 496 } 497 for (ssize_t i = 0 ; i < n ; i++) { 498 const char *name = attrs[i]; 499 size_t len = strlen(name); 500 size_t j = findPropIndex(name, len); 501 if (j >= mPropCount) { 502 // not there 503 continue; 504 } else if (j+1 == mPropCount) { 505 // last one, shorten 506 zapped++; 507 clearProp(&mProps[j]); 508 mPropCount--; 509 } else { 510 // in the middle, bring last one down and shorten 511 zapped++; 512 clearProp(&mProps[j]); 513 mProps[j] = mProps[mPropCount-1]; 514 mPropCount--; 515 } 516 } 517 return zapped; 518 } 519 520 // remove any keys NOT in the provided list 521 // return value is # keys removed 522 int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) { 523 int zapped = 0; 524 if (attrs == NULL || n <= 0) { 525 return -1; 526 } 527 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) { 528 Prop *prop = &mProps[i]; 529 for (ssize_t j = 0; j < n ; j++) { 530 if (strcmp(prop->mName, attrs[j]) == 0) { 531 clearProp(prop); 532 zapped++; 533 if (i != (ssize_t)(mPropCount-1)) { 534 *prop = mProps[mPropCount-1]; 535 } 536 initProp(&mProps[mPropCount-1]); 537 mPropCount--; 538 break; 539 } 540 } 541 } 542 return zapped; 543 } 544 545 // remove a single key 546 // return value is 0 (not found) or 1 (found and removed) 547 int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) { 548 return filter(1, &name); 549 } 550 551 // handle individual items/properties stored within the class 552 // 553 554 void MediaAnalyticsItem::initProp(Prop *prop) { 555 if (prop != NULL) { 556 prop->mName = NULL; 557 prop->mNameLen = 0; 558 559 prop->mType = kTypeNone; 560 } 561 } 562 563 void MediaAnalyticsItem::clearProp(Prop *prop) 564 { 565 if (prop != NULL) { 566 if (prop->mName != NULL) { 567 free((void *)prop->mName); 568 prop->mName = NULL; 569 prop->mNameLen = 0; 570 } 571 572 clearPropValue(prop); 573 } 574 } 575 576 void MediaAnalyticsItem::clearPropValue(Prop *prop) 577 { 578 if (prop != NULL) { 579 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) { 580 free(prop->u.CStringValue); 581 prop->u.CStringValue = NULL; 582 } 583 prop->mType = kTypeNone; 584 } 585 } 586 587 void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src) 588 { 589 // get rid of any pointers in the dst 590 clearProp(dst); 591 592 *dst = *src; 593 594 // fix any pointers that we blindly copied, so we have our own copies 595 if (dst->mName) { 596 void *p = malloc(dst->mNameLen + 1); 597 LOG_ALWAYS_FATAL_IF(p == NULL, 598 "failed malloc() duping property '%s' (len %zu)", 599 dst->mName, dst->mNameLen); 600 memcpy (p, src->mName, dst->mNameLen + 1); 601 dst->mName = (const char *) p; 602 } 603 if (dst->mType == kTypeCString) { 604 dst->u.CStringValue = strdup(src->u.CStringValue); 605 } 606 } 607 608 bool MediaAnalyticsItem::growProps(int increment) 609 { 610 if (increment <= 0) { 611 increment = kGrowProps; 612 } 613 int nsize = mPropSize + increment; 614 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize); 615 616 if (ni != NULL) { 617 for (int i = mPropSize; i < nsize; i++) { 618 initProp(&ni[i]); 619 } 620 mProps = ni; 621 mPropSize = nsize; 622 return true; 623 } else { 624 ALOGW("MediaAnalyticsItem::growProps fails"); 625 return false; 626 } 627 } 628 629 // Parcel / serialize things for binder calls 630 // 631 632 int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) { 633 // into 'this' object 634 // .. we make a copy of the string to put away. 635 mKey = data.readCString(); 636 mPid = data.readInt32(); 637 mUid = data.readInt32(); 638 mPkgName = data.readCString(); 639 mPkgVersionCode = data.readInt64(); 640 mSessionID = data.readInt64(); 641 // We no longer pay attention to user setting of finalized, BUT it's 642 // still part of the wire packet -- so read & discard. 643 mFinalized = data.readInt32(); 644 mFinalized = 1; 645 mTimestamp = data.readInt64(); 646 647 int count = data.readInt32(); 648 for (int i = 0; i < count ; i++) { 649 MediaAnalyticsItem::Attr attr = data.readCString(); 650 int32_t ztype = data.readInt32(); 651 switch (ztype) { 652 case MediaAnalyticsItem::kTypeInt32: 653 setInt32(attr, data.readInt32()); 654 break; 655 case MediaAnalyticsItem::kTypeInt64: 656 setInt64(attr, data.readInt64()); 657 break; 658 case MediaAnalyticsItem::kTypeDouble: 659 setDouble(attr, data.readDouble()); 660 break; 661 case MediaAnalyticsItem::kTypeCString: 662 setCString(attr, data.readCString()); 663 break; 664 case MediaAnalyticsItem::kTypeRate: 665 { 666 int64_t count = data.readInt64(); 667 int64_t duration = data.readInt64(); 668 setRate(attr, count, duration); 669 } 670 break; 671 default: 672 ALOGE("reading bad item type: %d, idx %d", 673 ztype, i); 674 return -1; 675 } 676 } 677 678 return 0; 679 } 680 681 int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) { 682 if (data == NULL) return -1; 683 684 685 data->writeCString(mKey.c_str()); 686 data->writeInt32(mPid); 687 data->writeInt32(mUid); 688 data->writeCString(mPkgName.c_str()); 689 data->writeInt64(mPkgVersionCode); 690 data->writeInt64(mSessionID); 691 data->writeInt32(mFinalized); 692 data->writeInt64(mTimestamp); 693 694 // set of items 695 int count = mPropCount; 696 data->writeInt32(count); 697 for (int i = 0 ; i < count; i++ ) { 698 Prop *prop = &mProps[i]; 699 data->writeCString(prop->mName); 700 data->writeInt32(prop->mType); 701 switch (prop->mType) { 702 case MediaAnalyticsItem::kTypeInt32: 703 data->writeInt32(prop->u.int32Value); 704 break; 705 case MediaAnalyticsItem::kTypeInt64: 706 data->writeInt64(prop->u.int64Value); 707 break; 708 case MediaAnalyticsItem::kTypeDouble: 709 data->writeDouble(prop->u.doubleValue); 710 break; 711 case MediaAnalyticsItem::kTypeRate: 712 data->writeInt64(prop->u.rate.count); 713 data->writeInt64(prop->u.rate.duration); 714 break; 715 case MediaAnalyticsItem::kTypeCString: 716 data->writeCString(prop->u.CStringValue); 717 break; 718 default: 719 ALOGE("found bad Prop type: %d, idx %d, name %s", 720 prop->mType, i, prop->mName); 721 break; 722 } 723 } 724 725 return 0; 726 } 727 728 729 std::string MediaAnalyticsItem::toString() { 730 return toString(PROTO_LAST); 731 } 732 733 std::string MediaAnalyticsItem::toString(int version) { 734 735 // v0 : released with 'o' 736 // v1 : bug fix (missing pid/finalized separator), 737 // adds apk name, apk version code 738 739 if (version <= PROTO_FIRST) { 740 // default to original v0 format, until proper parsers are in place 741 version = PROTO_V0; 742 } else if (version > PROTO_LAST) { 743 version = PROTO_LAST; 744 } 745 746 std::string result; 747 char buffer[512]; 748 749 if (version == PROTO_V0) { 750 result = "("; 751 } else { 752 snprintf(buffer, sizeof(buffer), "[%d:", version); 753 result.append(buffer); 754 } 755 756 // same order as we spill into the parcel, although not required 757 // key+session are our primary matching criteria 758 result.append(mKey.c_str()); 759 result.append(":"); 760 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID); 761 result.append(buffer); 762 763 snprintf(buffer, sizeof(buffer), "%d:", mUid); 764 result.append(buffer); 765 766 if (version >= PROTO_V1) { 767 result.append(mPkgName); 768 snprintf(buffer, sizeof(buffer), ":%" PRId64 ":", mPkgVersionCode); 769 result.append(buffer); 770 } 771 772 // in 'o' (v1) , the separator between pid and finalized was omitted 773 if (version <= PROTO_V0) { 774 snprintf(buffer, sizeof(buffer), "%d", mPid); 775 } else { 776 snprintf(buffer, sizeof(buffer), "%d:", mPid); 777 } 778 result.append(buffer); 779 780 snprintf(buffer, sizeof(buffer), "%d:", mFinalized); 781 result.append(buffer); 782 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp); 783 result.append(buffer); 784 785 // set of items 786 int count = mPropCount; 787 snprintf(buffer, sizeof(buffer), "%d:", count); 788 result.append(buffer); 789 for (int i = 0 ; i < count; i++ ) { 790 Prop *prop = &mProps[i]; 791 switch (prop->mType) { 792 case MediaAnalyticsItem::kTypeInt32: 793 snprintf(buffer,sizeof(buffer), 794 "%s=%d:", prop->mName, prop->u.int32Value); 795 break; 796 case MediaAnalyticsItem::kTypeInt64: 797 snprintf(buffer,sizeof(buffer), 798 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value); 799 break; 800 case MediaAnalyticsItem::kTypeDouble: 801 snprintf(buffer,sizeof(buffer), 802 "%s=%e:", prop->mName, prop->u.doubleValue); 803 break; 804 case MediaAnalyticsItem::kTypeRate: 805 snprintf(buffer,sizeof(buffer), 806 "%s=%" PRId64 "/%" PRId64 ":", prop->mName, 807 prop->u.rate.count, prop->u.rate.duration); 808 break; 809 case MediaAnalyticsItem::kTypeCString: 810 snprintf(buffer,sizeof(buffer), "%s=", prop->mName); 811 result.append(buffer); 812 // XXX: sanitize string for ':' '=' 813 result.append(prop->u.CStringValue); 814 buffer[0] = ':'; 815 buffer[1] = '\0'; 816 break; 817 default: 818 ALOGE("to_String bad item type: %d for %s", 819 prop->mType, prop->mName); 820 break; 821 } 822 result.append(buffer); 823 } 824 825 if (version == PROTO_V0) { 826 result.append(")"); 827 } else { 828 result.append("]"); 829 } 830 831 return result; 832 } 833 834 // for the lazy, we offer methods that finds the service and 835 // calls the appropriate daemon 836 bool MediaAnalyticsItem::selfrecord() { 837 return selfrecord(false); 838 } 839 840 bool MediaAnalyticsItem::selfrecord(bool forcenew) { 841 842 if (DEBUG_API) { 843 std::string p = this->toString(); 844 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew); 845 } 846 847 sp<IMediaAnalyticsService> svc = getInstance(); 848 849 if (svc != NULL) { 850 MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew); 851 if (newid == SessionIDInvalid) { 852 std::string p = this->toString(); 853 ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew); 854 return false; 855 } 856 return true; 857 } else { 858 std::string p = this->toString(); 859 ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew); 860 return false; 861 } 862 } 863 864 // get a connection we can reuse for most of our lifetime 865 // static 866 sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService; 867 static Mutex sInitMutex; 868 static int remainingBindAttempts = SVC_TRIES; 869 870 //static 871 bool MediaAnalyticsItem::isEnabled() { 872 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1); 873 874 if (enabled == -1) { 875 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1); 876 } 877 if (enabled == -1) { 878 enabled = MediaAnalyticsItem::EnabledProperty_default; 879 } 880 if (enabled <= 0) { 881 return false; 882 } 883 return true; 884 } 885 886 887 // monitor health of our connection to the metrics service 888 class MediaMetricsDeathNotifier : public IBinder::DeathRecipient { 889 virtual void binderDied(const wp<IBinder> &) { 890 ALOGW("Reacquire service connection on next request"); 891 MediaAnalyticsItem::dropInstance(); 892 } 893 }; 894 895 static sp<MediaMetricsDeathNotifier> sNotifier = NULL; 896 897 // static 898 void MediaAnalyticsItem::dropInstance() { 899 Mutex::Autolock _l(sInitMutex); 900 remainingBindAttempts = SVC_TRIES; 901 sAnalyticsService = NULL; 902 } 903 904 //static 905 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() { 906 907 static const char *servicename = "media.metrics"; 908 int enabled = isEnabled(); 909 910 if (enabled == false) { 911 if (DEBUG_SERVICEACCESS) { 912 ALOGD("disabled"); 913 } 914 return NULL; 915 } 916 917 // completely skip logging from certain UIDs. We do this here 918 // to avoid the multi-second timeouts while we learn that 919 // sepolicy will not let us find the service. 920 // We do this only for a select set of UIDs 921 // The sepolicy protection is still in place, we just want a faster 922 // response from this specific, small set of uids. 923 { 924 uid_t uid = getuid(); 925 switch (uid) { 926 case AID_RADIO: // telephony subsystem, RIL 927 return NULL; 928 break; 929 default: 930 // let sepolicy deny access if appropriate 931 break; 932 } 933 } 934 935 { 936 Mutex::Autolock _l(sInitMutex); 937 const char *badness = ""; 938 939 // think of remainingBindAttempts as telling us whether service==NULL because 940 // (1) we haven't tried to initialize it yet 941 // (2) we've tried to initialize it, but failed. 942 if (sAnalyticsService == NULL && remainingBindAttempts > 0) { 943 sp<IServiceManager> sm = defaultServiceManager(); 944 if (sm != NULL) { 945 sp<IBinder> binder = sm->getService(String16(servicename)); 946 if (binder != NULL) { 947 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder); 948 if (sNotifier != NULL) { 949 sNotifier = NULL; 950 } 951 sNotifier = new MediaMetricsDeathNotifier(); 952 binder->linkToDeath(sNotifier); 953 } else { 954 badness = "did not find service"; 955 } 956 } else { 957 badness = "No Service Manager access"; 958 } 959 960 if (sAnalyticsService == NULL) { 961 if (remainingBindAttempts > 0) { 962 remainingBindAttempts--; 963 } 964 if (DEBUG_SERVICEACCESS) { 965 ALOGD("Unable to bind to service %s: %s", servicename, badness); 966 } 967 } 968 } 969 970 return sAnalyticsService; 971 } 972 } 973 974 // merge the info from 'incoming' into this record. 975 // we finish with a union of this+incoming and special handling for collisions 976 bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) { 977 978 // if I don't have key or session id, take them from incoming 979 // 'this' should never be missing both of them... 980 if (mKey.empty()) { 981 mKey = incoming->mKey; 982 } else if (mSessionID == 0) { 983 mSessionID = incoming->mSessionID; 984 } 985 986 // for each attribute from 'incoming', resolve appropriately 987 int nattr = incoming->mPropCount; 988 for (int i = 0 ; i < nattr; i++ ) { 989 Prop *iprop = &incoming->mProps[i]; 990 const char *p = iprop->mName; 991 size_t len = strlen(p); 992 993 // should ignore a zero length name... 994 if (len == 0) { 995 continue; 996 } 997 998 Prop *oprop = findProp(iprop->mName); 999 1000 if (oprop == NULL) { 1001 // no oprop, so we insert the new one 1002 oprop = allocateProp(p); 1003 if (oprop != NULL) { 1004 copyProp(oprop, iprop); 1005 } else { 1006 ALOGW("dropped property '%s'", iprop->mName); 1007 } 1008 } else { 1009 copyProp(oprop, iprop); 1010 } 1011 } 1012 1013 // not sure when we'd return false... 1014 return true; 1015 } 1016 1017 } // namespace android 1018 1019