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 <media/stagefright/foundation/AString.h> 33 34 #include <binder/IServiceManager.h> 35 #include <media/IMediaAnalyticsService.h> 36 #include <media/MediaAnalyticsItem.h> 37 #include <private/android_filesystem_config.h> 38 39 namespace android { 40 41 #define DEBUG_SERVICEACCESS 0 42 #define DEBUG_API 0 43 #define DEBUG_ALLOCATIONS 0 44 45 // after this many failed attempts, we stop trying [from this process] and just say that 46 // the service is off. 47 #define SVC_TRIES 2 48 49 // the few universal keys we have 50 const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any"; 51 const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone = "none"; 52 53 const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled"; 54 const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled"; 55 const int MediaAnalyticsItem::EnabledProperty_default = 1; 56 57 58 // access functions for the class 59 MediaAnalyticsItem::MediaAnalyticsItem() 60 : mPid(-1), 61 mUid(-1), 62 mSessionID(MediaAnalyticsItem::SessionIDNone), 63 mTimestamp(0), 64 mFinalized(0), 65 mPropCount(0), mPropSize(0), mProps(NULL) 66 { 67 mKey = MediaAnalyticsItem::kKeyNone; 68 } 69 70 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key) 71 : mPid(-1), 72 mUid(-1), 73 mSessionID(MediaAnalyticsItem::SessionIDNone), 74 mTimestamp(0), 75 mFinalized(0), 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 < mPropSize; 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->mSessionID = this->mSessionID; 124 dst->mTimestamp = this->mTimestamp; 125 dst->mFinalized = this->mFinalized; 126 127 // properties aka attributes 128 dst->growProps(this->mPropCount); 129 for(size_t i=0;i<mPropCount;i++) { 130 copyProp(&dst->mProps[i], &this->mProps[i]); 131 } 132 dst->mPropCount = this->mPropCount; 133 } 134 135 return dst; 136 } 137 138 // so clients can send intermediate values to be overlaid later 139 MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) { 140 mFinalized = value; 141 return *this; 142 } 143 144 bool MediaAnalyticsItem::getFinalized() const { 145 return mFinalized; 146 } 147 148 MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) { 149 mSessionID = id; 150 return *this; 151 } 152 153 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const { 154 return mSessionID; 155 } 156 157 MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() { 158 159 if (mSessionID == SessionIDNone) { 160 // get one from the server 161 MediaAnalyticsItem::SessionID_t newid = SessionIDNone; 162 sp<IMediaAnalyticsService> svc = getInstance(); 163 if (svc != NULL) { 164 newid = svc->generateUniqueSessionID(); 165 } 166 mSessionID = newid; 167 } 168 169 return mSessionID; 170 } 171 172 MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() { 173 mSessionID = MediaAnalyticsItem::SessionIDNone; 174 return *this; 175 } 176 177 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) { 178 mTimestamp = ts; 179 return *this; 180 } 181 182 nsecs_t MediaAnalyticsItem::getTimestamp() const { 183 return mTimestamp; 184 } 185 186 MediaAnalyticsItem &MediaAnalyticsItem::setPid(pid_t pid) { 187 mPid = pid; 188 return *this; 189 } 190 191 pid_t MediaAnalyticsItem::getPid() const { 192 return mPid; 193 } 194 195 MediaAnalyticsItem &MediaAnalyticsItem::setUid(uid_t uid) { 196 mUid = uid; 197 return *this; 198 } 199 200 uid_t MediaAnalyticsItem::getUid() const { 201 return mUid; 202 } 203 204 // this key is for the overall record -- "codec", "player", "drm", etc 205 MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) { 206 mKey = key; 207 return *this; 208 } 209 210 MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() { 211 return mKey; 212 } 213 214 // number of attributes we have in this record 215 int32_t MediaAnalyticsItem::count() const { 216 return mPropCount; 217 } 218 219 // find the proper entry in the list 220 size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len) 221 { 222 size_t i = 0; 223 for (; i < mPropCount; i++) { 224 Prop *prop = &mProps[i]; 225 if (prop->mNameLen != len) { 226 continue; 227 } 228 if (memcmp(name, prop->mName, len) == 0) { 229 break; 230 } 231 } 232 return i; 233 } 234 235 MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) { 236 size_t len = strlen(name); 237 size_t i = findPropIndex(name, len); 238 if (i < mPropCount) { 239 return &mProps[i]; 240 } 241 return NULL; 242 } 243 244 void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) { 245 mNameLen = len; 246 mName = (const char *) malloc(len+1); 247 memcpy ((void *)mName, name, len+1); 248 } 249 250 // used only as part of a storing operation 251 MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) { 252 size_t len = strlen(name); 253 size_t i = findPropIndex(name, len); 254 Prop *prop; 255 256 if (i < mPropCount) { 257 prop = &mProps[i]; 258 } else { 259 if (i == mPropSize) { 260 growProps(); 261 // XXX: verify success 262 } 263 i = mPropCount++; 264 prop = &mProps[i]; 265 prop->setName(name, len); 266 } 267 268 return prop; 269 } 270 271 // set the values 272 void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) { 273 Prop *prop = allocateProp(name); 274 prop->mType = kTypeInt32; 275 prop->u.int32Value = value; 276 } 277 278 void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) { 279 Prop *prop = allocateProp(name); 280 prop->mType = kTypeInt64; 281 prop->u.int64Value = value; 282 } 283 284 void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) { 285 Prop *prop = allocateProp(name); 286 prop->mType = kTypeDouble; 287 prop->u.doubleValue = value; 288 } 289 290 void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) { 291 292 Prop *prop = allocateProp(name); 293 // any old value will be gone 294 prop->mType = kTypeCString; 295 prop->u.CStringValue = strdup(value); 296 } 297 298 void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) { 299 Prop *prop = allocateProp(name); 300 prop->mType = kTypeRate; 301 prop->u.rate.count = count; 302 prop->u.rate.duration = duration; 303 } 304 305 306 // find/add/set fused into a single operation 307 void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) { 308 Prop *prop = allocateProp(name); 309 switch (prop->mType) { 310 case kTypeInt32: 311 prop->u.int32Value += value; 312 break; 313 default: 314 clearPropValue(prop); 315 prop->mType = kTypeInt32; 316 prop->u.int32Value = value; 317 break; 318 } 319 } 320 321 void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) { 322 Prop *prop = allocateProp(name); 323 switch (prop->mType) { 324 case kTypeInt64: 325 prop->u.int64Value += value; 326 break; 327 default: 328 clearPropValue(prop); 329 prop->mType = kTypeInt64; 330 prop->u.int64Value = value; 331 break; 332 } 333 } 334 335 void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) { 336 Prop *prop = allocateProp(name); 337 switch (prop->mType) { 338 case kTypeRate: 339 prop->u.rate.count += count; 340 prop->u.rate.duration += duration; 341 break; 342 default: 343 clearPropValue(prop); 344 prop->mType = kTypeRate; 345 prop->u.rate.count = count; 346 prop->u.rate.duration = duration; 347 break; 348 } 349 } 350 351 void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) { 352 Prop *prop = allocateProp(name); 353 switch (prop->mType) { 354 case kTypeDouble: 355 prop->u.doubleValue += value; 356 break; 357 default: 358 clearPropValue(prop); 359 prop->mType = kTypeDouble; 360 prop->u.doubleValue = value; 361 break; 362 } 363 } 364 365 // find & extract values 366 bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) { 367 Prop *prop = findProp(name); 368 if (prop == NULL || prop->mType != kTypeInt32) { 369 return false; 370 } 371 if (value != NULL) { 372 *value = prop->u.int32Value; 373 } 374 return true; 375 } 376 377 bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) { 378 Prop *prop = findProp(name); 379 if (prop == NULL || prop->mType != kTypeInt64) { 380 return false; 381 } 382 if (value != NULL) { 383 *value = prop->u.int64Value; 384 } 385 return true; 386 } 387 388 bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) { 389 Prop *prop = findProp(name); 390 if (prop == NULL || prop->mType != kTypeRate) { 391 return false; 392 } 393 if (count != NULL) { 394 *count = prop->u.rate.count; 395 } 396 if (duration != NULL) { 397 *duration = prop->u.rate.duration; 398 } 399 if (rate != NULL) { 400 double r = 0.0; 401 if (prop->u.rate.duration != 0) { 402 r = prop->u.rate.count / (double) prop->u.rate.duration; 403 } 404 *rate = r; 405 } 406 return true; 407 } 408 409 bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) { 410 Prop *prop = findProp(name); 411 if (prop == NULL || prop->mType != kTypeDouble) { 412 return false; 413 } 414 if (value != NULL) { 415 *value = prop->u.doubleValue; 416 } 417 return true; 418 } 419 420 // caller responsible for the returned string 421 bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) { 422 Prop *prop = findProp(name); 423 if (prop == NULL || prop->mType != kTypeDouble) { 424 return false; 425 } 426 if (value != NULL) { 427 *value = strdup(prop->u.CStringValue); 428 } 429 return true; 430 } 431 432 // remove indicated keys and their values 433 // return value is # keys removed 434 int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) { 435 int zapped = 0; 436 if (attrs == NULL || n <= 0) { 437 return -1; 438 } 439 for (ssize_t i = 0 ; i < n ; i++) { 440 const char *name = attrs[i]; 441 size_t len = strlen(name); 442 size_t j = findPropIndex(name, len); 443 if (j >= mPropCount) { 444 // not there 445 continue; 446 } else if (j+1 == mPropCount) { 447 // last one, shorten 448 zapped++; 449 clearProp(&mProps[j]); 450 mPropCount--; 451 } else { 452 // in the middle, bring last one down and shorten 453 zapped++; 454 clearProp(&mProps[j]); 455 mProps[j] = mProps[mPropCount-1]; 456 mPropCount--; 457 } 458 } 459 return zapped; 460 } 461 462 // remove any keys NOT in the provided list 463 // return value is # keys removed 464 int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) { 465 int zapped = 0; 466 if (attrs == NULL || n <= 0) { 467 return -1; 468 } 469 for (ssize_t i = mPropCount-1 ; i >=0 ; i--) { 470 Prop *prop = &mProps[i]; 471 for (ssize_t j = 0; j < n ; j++) { 472 if (strcmp(prop->mName, attrs[j]) == 0) { 473 clearProp(prop); 474 zapped++; 475 if (i != (ssize_t)(mPropCount-1)) { 476 *prop = mProps[mPropCount-1]; 477 } 478 initProp(&mProps[mPropCount-1]); 479 mPropCount--; 480 break; 481 } 482 } 483 } 484 return zapped; 485 } 486 487 // remove a single key 488 // return value is 0 (not found) or 1 (found and removed) 489 int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) { 490 return filter(1, &name); 491 } 492 493 // handle individual items/properties stored within the class 494 // 495 496 void MediaAnalyticsItem::initProp(Prop *prop) { 497 if (prop != NULL) { 498 prop->mName = NULL; 499 prop->mNameLen = 0; 500 501 prop->mType = kTypeNone; 502 } 503 } 504 505 void MediaAnalyticsItem::clearProp(Prop *prop) 506 { 507 if (prop != NULL) { 508 if (prop->mName != NULL) { 509 free((void *)prop->mName); 510 prop->mName = NULL; 511 prop->mNameLen = 0; 512 } 513 514 clearPropValue(prop); 515 } 516 } 517 518 void MediaAnalyticsItem::clearPropValue(Prop *prop) 519 { 520 if (prop != NULL) { 521 if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) { 522 free(prop->u.CStringValue); 523 prop->u.CStringValue = NULL; 524 } 525 prop->mType = kTypeNone; 526 } 527 } 528 529 void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src) 530 { 531 // get rid of any pointers in the dst 532 clearProp(dst); 533 534 *dst = *src; 535 536 // fix any pointers that we blindly copied, so we have our own copies 537 if (dst->mName) { 538 void *p = malloc(dst->mNameLen + 1); 539 memcpy (p, src->mName, dst->mNameLen + 1); 540 dst->mName = (const char *) p; 541 } 542 if (dst->mType == kTypeCString) { 543 dst->u.CStringValue = strdup(src->u.CStringValue); 544 } 545 } 546 547 void MediaAnalyticsItem::growProps(int increment) 548 { 549 if (increment <= 0) { 550 increment = kGrowProps; 551 } 552 int nsize = mPropSize + increment; 553 Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize); 554 555 if (ni != NULL) { 556 for (int i = mPropSize; i < nsize; i++) { 557 initProp(&ni[i]); 558 } 559 mProps = ni; 560 mPropSize = nsize; 561 } 562 } 563 564 // Parcel / serialize things for binder calls 565 // 566 567 int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) { 568 // into 'this' object 569 // .. we make a copy of the string to put away. 570 mKey = data.readCString(); 571 mSessionID = data.readInt64(); 572 mFinalized = data.readInt32(); 573 mTimestamp = data.readInt64(); 574 575 int count = data.readInt32(); 576 for (int i = 0; i < count ; i++) { 577 MediaAnalyticsItem::Attr attr = data.readCString(); 578 int32_t ztype = data.readInt32(); 579 switch (ztype) { 580 case MediaAnalyticsItem::kTypeInt32: 581 setInt32(attr, data.readInt32()); 582 break; 583 case MediaAnalyticsItem::kTypeInt64: 584 setInt64(attr, data.readInt64()); 585 break; 586 case MediaAnalyticsItem::kTypeDouble: 587 setDouble(attr, data.readDouble()); 588 break; 589 case MediaAnalyticsItem::kTypeCString: 590 setCString(attr, data.readCString()); 591 break; 592 case MediaAnalyticsItem::kTypeRate: 593 { 594 int64_t count = data.readInt64(); 595 int64_t duration = data.readInt64(); 596 setRate(attr, count, duration); 597 } 598 break; 599 default: 600 ALOGE("reading bad item type: %d, idx %d", 601 ztype, i); 602 return -1; 603 } 604 } 605 606 return 0; 607 } 608 609 int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) { 610 if (data == NULL) return -1; 611 612 613 data->writeCString(mKey.c_str()); 614 data->writeInt64(mSessionID); 615 data->writeInt32(mFinalized); 616 data->writeInt64(mTimestamp); 617 618 // set of items 619 int count = mPropCount; 620 data->writeInt32(count); 621 for (int i = 0 ; i < count; i++ ) { 622 Prop *prop = &mProps[i]; 623 data->writeCString(prop->mName); 624 data->writeInt32(prop->mType); 625 switch (prop->mType) { 626 case MediaAnalyticsItem::kTypeInt32: 627 data->writeInt32(prop->u.int32Value); 628 break; 629 case MediaAnalyticsItem::kTypeInt64: 630 data->writeInt64(prop->u.int64Value); 631 break; 632 case MediaAnalyticsItem::kTypeDouble: 633 data->writeDouble(prop->u.doubleValue); 634 break; 635 case MediaAnalyticsItem::kTypeRate: 636 data->writeInt64(prop->u.rate.count); 637 data->writeInt64(prop->u.rate.duration); 638 break; 639 case MediaAnalyticsItem::kTypeCString: 640 data->writeCString(prop->u.CStringValue); 641 break; 642 default: 643 ALOGE("found bad Prop type: %d, idx %d, name %s", 644 prop->mType, i, prop->mName); 645 break; 646 } 647 } 648 649 return 0; 650 } 651 652 653 AString MediaAnalyticsItem::toString() { 654 655 AString result = "("; 656 char buffer[512]; 657 658 // same order as we spill into the parcel, although not required 659 // key+session are our primary matching criteria 660 //RBE ALOGD("mKey.c_str"); 661 result.append(mKey.c_str()); 662 //RBE ALOGD("post-mKey.c_str"); 663 result.append(":"); 664 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID); 665 result.append(buffer); 666 667 // we need these internally, but don't want to upload them 668 snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid); 669 result.append(buffer); 670 671 snprintf(buffer, sizeof(buffer), "%d:", mFinalized); 672 result.append(buffer); 673 snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp); 674 result.append(buffer); 675 676 // set of items 677 int count = mPropCount; 678 snprintf(buffer, sizeof(buffer), "%d:", count); 679 result.append(buffer); 680 for (int i = 0 ; i < count; i++ ) { 681 Prop *prop = &mProps[i]; 682 switch (prop->mType) { 683 case MediaAnalyticsItem::kTypeInt32: 684 snprintf(buffer,sizeof(buffer), 685 "%s=%d:", prop->mName, prop->u.int32Value); 686 break; 687 case MediaAnalyticsItem::kTypeInt64: 688 snprintf(buffer,sizeof(buffer), 689 "%s=%" PRId64 ":", prop->mName, prop->u.int64Value); 690 break; 691 case MediaAnalyticsItem::kTypeDouble: 692 snprintf(buffer,sizeof(buffer), 693 "%s=%e:", prop->mName, prop->u.doubleValue); 694 break; 695 case MediaAnalyticsItem::kTypeRate: 696 snprintf(buffer,sizeof(buffer), 697 "%s=%" PRId64 "/%" PRId64 ":", prop->mName, 698 prop->u.rate.count, prop->u.rate.duration); 699 break; 700 case MediaAnalyticsItem::kTypeCString: 701 snprintf(buffer,sizeof(buffer), "%s=", prop->mName); 702 result.append(buffer); 703 // XXX: sanitize string for ':' '=' 704 result.append(prop->u.CStringValue); 705 buffer[0] = ':'; 706 buffer[1] = '\0'; 707 break; 708 default: 709 ALOGE("to_String bad item type: %d for %s", 710 prop->mType, prop->mName); 711 break; 712 } 713 result.append(buffer); 714 } 715 716 result.append(")"); 717 718 return result; 719 } 720 721 // for the lazy, we offer methods that finds the service and 722 // calls the appropriate daemon 723 bool MediaAnalyticsItem::selfrecord() { 724 return selfrecord(false); 725 } 726 727 bool MediaAnalyticsItem::selfrecord(bool forcenew) { 728 729 if (DEBUG_API) { 730 AString p = this->toString(); 731 ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew); 732 } 733 734 sp<IMediaAnalyticsService> svc = getInstance(); 735 736 if (svc != NULL) { 737 svc->submit(this, forcenew); 738 return true; 739 } else { 740 AString p = this->toString(); 741 ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew); 742 return false; 743 } 744 } 745 746 // get a connection we can reuse for most of our lifetime 747 // static 748 sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService; 749 static Mutex sInitMutex; 750 751 //static 752 bool MediaAnalyticsItem::isEnabled() { 753 int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1); 754 755 if (enabled == -1) { 756 enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1); 757 } 758 if (enabled == -1) { 759 enabled = MediaAnalyticsItem::EnabledProperty_default; 760 } 761 if (enabled <= 0) { 762 return false; 763 } 764 return true; 765 } 766 767 //static 768 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() { 769 static const char *servicename = "media.metrics"; 770 static int tries_remaining = SVC_TRIES; 771 int enabled = isEnabled(); 772 773 if (enabled == false) { 774 if (DEBUG_SERVICEACCESS) { 775 ALOGD("disabled"); 776 } 777 return NULL; 778 } 779 780 // completely skip logging from certain UIDs. We do this here 781 // to avoid the multi-second timeouts while we learn that 782 // sepolicy will not let us find the service. 783 // We do this only for a select set of UIDs 784 // The sepolicy protection is still in place, we just want a faster 785 // response from this specific, small set of uids. 786 { 787 uid_t uid = getuid(); 788 switch (uid) { 789 case AID_RADIO: // telephony subsystem, RIL 790 return NULL; 791 break; 792 default: 793 // let sepolicy deny access if appropriate 794 break; 795 } 796 } 797 798 { 799 Mutex::Autolock _l(sInitMutex); 800 const char *badness = ""; 801 802 // think of tries_remaining as telling us whether service==NULL because 803 // (1) we haven't tried to initialize it yet 804 // (2) we've tried to initialize it, but failed. 805 if (sAnalyticsService == NULL && tries_remaining > 0) { 806 sp<IServiceManager> sm = defaultServiceManager(); 807 if (sm != NULL) { 808 sp<IBinder> binder = sm->getService(String16(servicename)); 809 if (binder != NULL) { 810 sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder); 811 } else { 812 badness = "did not find service"; 813 } 814 } else { 815 badness = "No Service Manager access"; 816 } 817 818 if (sAnalyticsService == NULL) { 819 if (tries_remaining > 0) { 820 tries_remaining--; 821 } 822 if (DEBUG_SERVICEACCESS) { 823 ALOGD("Unable to bind to service %s: %s", servicename, badness); 824 } 825 } 826 } 827 828 return sAnalyticsService; 829 } 830 } 831 832 833 // merge the info from 'incoming' into this record. 834 // we finish with a union of this+incoming and special handling for collisions 835 bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) { 836 837 // if I don't have key or session id, take them from incoming 838 // 'this' should never be missing both of them... 839 if (mKey.empty()) { 840 mKey = incoming->mKey; 841 } else if (mSessionID == 0) { 842 mSessionID = incoming->mSessionID; 843 } 844 845 // we always take the more recent 'finalized' value 846 setFinalized(incoming->getFinalized()); 847 848 // for each attribute from 'incoming', resolve appropriately 849 int nattr = incoming->mPropCount; 850 for (int i = 0 ; i < nattr; i++ ) { 851 Prop *iprop = &incoming->mProps[i]; 852 Prop *oprop = findProp(iprop->mName); 853 const char *p = iprop->mName; 854 size_t len = strlen(p); 855 char semantic = p[len-1]; 856 857 if (oprop == NULL) { 858 // no oprop, so we insert the new one 859 oprop = allocateProp(p); 860 copyProp(oprop, iprop); 861 } else { 862 // merge iprop into oprop 863 switch (semantic) { 864 case '<': // first aka keep old) 865 /* nop */ 866 break; 867 868 default: // default is 'last' 869 case '>': // last (aka keep new) 870 copyProp(oprop, iprop); 871 break; 872 873 case '+': /* sum */ 874 // XXX validate numeric types, sum in place 875 break; 876 877 } 878 } 879 } 880 881 // not sure when we'd return false... 882 return true; 883 } 884 885 } // namespace android 886 887