1 /* 2 * Copyright (C) 2010 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 #define LOG_TAG "AMessage" 18 //#define LOG_NDEBUG 0 19 //#define DUMP_STATS 20 #include <cutils/log.h> 21 22 #include "AMessage.h" 23 24 #include <ctype.h> 25 26 #include "AAtomizer.h" 27 #include "ABuffer.h" 28 #include "ADebug.h" 29 #include "ALooperRoster.h" 30 #include "AString.h" 31 32 #include <binder/Parcel.h> 33 #include <media/stagefright/foundation/hexdump.h> 34 35 namespace android { 36 37 extern ALooperRoster gLooperRoster; 38 39 AMessage::AMessage(uint32_t what, ALooper::handler_id target) 40 : mWhat(what), 41 mTarget(target), 42 mNumItems(0) { 43 } 44 45 AMessage::~AMessage() { 46 clear(); 47 } 48 49 void AMessage::setWhat(uint32_t what) { 50 mWhat = what; 51 } 52 53 uint32_t AMessage::what() const { 54 return mWhat; 55 } 56 57 void AMessage::setTarget(ALooper::handler_id handlerID) { 58 mTarget = handlerID; 59 } 60 61 ALooper::handler_id AMessage::target() const { 62 return mTarget; 63 } 64 65 void AMessage::clear() { 66 for (size_t i = 0; i < mNumItems; ++i) { 67 Item *item = &mItems[i]; 68 delete[] item->mName; 69 item->mName = NULL; 70 freeItemValue(item); 71 } 72 mNumItems = 0; 73 } 74 75 void AMessage::freeItemValue(Item *item) { 76 switch (item->mType) { 77 case kTypeString: 78 { 79 delete item->u.stringValue; 80 break; 81 } 82 83 case kTypeObject: 84 case kTypeMessage: 85 case kTypeBuffer: 86 { 87 if (item->u.refValue != NULL) { 88 item->u.refValue->decStrong(this); 89 } 90 break; 91 } 92 93 default: 94 break; 95 } 96 } 97 98 #ifdef DUMP_STATS 99 #include <utils/Mutex.h> 100 101 Mutex gLock; 102 static int32_t gFindItemCalls = 1; 103 static int32_t gDupCalls = 1; 104 static int32_t gAverageNumItems = 0; 105 static int32_t gAverageNumChecks = 0; 106 static int32_t gAverageNumMemChecks = 0; 107 static int32_t gAverageDupItems = 0; 108 static int32_t gLastChecked = -1; 109 110 static void reportStats() { 111 int32_t time = (ALooper::GetNowUs() / 1000); 112 if (time / 1000 != gLastChecked / 1000) { 113 gLastChecked = time; 114 ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)", 115 gFindItemCalls, 116 gAverageNumItems / (float)gFindItemCalls, 117 gAverageNumChecks / (float)gFindItemCalls, 118 gAverageNumMemChecks / (float)gFindItemCalls, 119 gDupCalls, 120 gAverageDupItems / (float)gDupCalls); 121 gFindItemCalls = gDupCalls = 1; 122 gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0; 123 gLastChecked = time; 124 } 125 } 126 #endif 127 128 inline size_t AMessage::findItemIndex(const char *name, size_t len) const { 129 #ifdef DUMP_STATS 130 size_t memchecks = 0; 131 #endif 132 size_t i = 0; 133 for (; i < mNumItems; i++) { 134 if (len != mItems[i].mNameLength) { 135 continue; 136 } 137 #ifdef DUMP_STATS 138 ++memchecks; 139 #endif 140 if (!memcmp(mItems[i].mName, name, len)) { 141 break; 142 } 143 } 144 #ifdef DUMP_STATS 145 { 146 Mutex::Autolock _l(gLock); 147 ++gFindItemCalls; 148 gAverageNumItems += mNumItems; 149 gAverageNumMemChecks += memchecks; 150 gAverageNumChecks += i; 151 reportStats(); 152 } 153 #endif 154 return i; 155 } 156 157 // assumes item's name was uninitialized or NULL 158 void AMessage::Item::setName(const char *name, size_t len) { 159 mNameLength = len; 160 mName = new char[len + 1]; 161 memcpy((void*)mName, name, len + 1); 162 } 163 164 AMessage::Item *AMessage::allocateItem(const char *name) { 165 size_t len = strlen(name); 166 size_t i = findItemIndex(name, len); 167 Item *item; 168 169 if (i < mNumItems) { 170 item = &mItems[i]; 171 freeItemValue(item); 172 } else { 173 CHECK(mNumItems < kMaxNumItems); 174 i = mNumItems++; 175 item = &mItems[i]; 176 item->setName(name, len); 177 } 178 179 return item; 180 } 181 182 const AMessage::Item *AMessage::findItem( 183 const char *name, Type type) const { 184 size_t i = findItemIndex(name, strlen(name)); 185 if (i < mNumItems) { 186 const Item *item = &mItems[i]; 187 return item->mType == type ? item : NULL; 188 189 } 190 return NULL; 191 } 192 193 bool AMessage::contains(const char *name) const { 194 size_t i = findItemIndex(name, strlen(name)); 195 return i < mNumItems; 196 } 197 198 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \ 199 void AMessage::set##NAME(const char *name, TYPENAME value) { \ 200 Item *item = allocateItem(name); \ 201 \ 202 item->mType = kType##NAME; \ 203 item->u.FIELDNAME = value; \ 204 } \ 205 \ 206 bool AMessage::find##NAME(const char *name, TYPENAME *value) const { \ 207 const Item *item = findItem(name, kType##NAME); \ 208 if (item) { \ 209 *value = item->u.FIELDNAME; \ 210 return true; \ 211 } \ 212 return false; \ 213 } 214 215 BASIC_TYPE(Int32,int32Value,int32_t) 216 BASIC_TYPE(Int64,int64Value,int64_t) 217 BASIC_TYPE(Size,sizeValue,size_t) 218 BASIC_TYPE(Float,floatValue,float) 219 BASIC_TYPE(Double,doubleValue,double) 220 BASIC_TYPE(Pointer,ptrValue,void *) 221 222 #undef BASIC_TYPE 223 224 void AMessage::setString( 225 const char *name, const char *s, ssize_t len) { 226 Item *item = allocateItem(name); 227 item->mType = kTypeString; 228 item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len); 229 } 230 231 void AMessage::setString( 232 const char *name, const AString &s) { 233 setString(name, s.c_str(), s.size()); 234 } 235 236 void AMessage::setObjectInternal( 237 const char *name, const sp<RefBase> &obj, Type type) { 238 Item *item = allocateItem(name); 239 item->mType = type; 240 241 if (obj != NULL) { obj->incStrong(this); } 242 item->u.refValue = obj.get(); 243 } 244 245 void AMessage::setObject(const char *name, const sp<RefBase> &obj) { 246 setObjectInternal(name, obj, kTypeObject); 247 } 248 249 void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) { 250 setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer); 251 } 252 253 void AMessage::setMessage(const char *name, const sp<AMessage> &obj) { 254 Item *item = allocateItem(name); 255 item->mType = kTypeMessage; 256 257 if (obj != NULL) { obj->incStrong(this); } 258 item->u.refValue = obj.get(); 259 } 260 261 void AMessage::setRect( 262 const char *name, 263 int32_t left, int32_t top, int32_t right, int32_t bottom) { 264 Item *item = allocateItem(name); 265 item->mType = kTypeRect; 266 267 item->u.rectValue.mLeft = left; 268 item->u.rectValue.mTop = top; 269 item->u.rectValue.mRight = right; 270 item->u.rectValue.mBottom = bottom; 271 } 272 273 bool AMessage::findString(const char *name, AString *value) const { 274 const Item *item = findItem(name, kTypeString); 275 if (item) { 276 *value = *item->u.stringValue; 277 return true; 278 } 279 return false; 280 } 281 282 bool AMessage::findObject(const char *name, sp<RefBase> *obj) const { 283 const Item *item = findItem(name, kTypeObject); 284 if (item) { 285 *obj = item->u.refValue; 286 return true; 287 } 288 return false; 289 } 290 291 bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const { 292 const Item *item = findItem(name, kTypeBuffer); 293 if (item) { 294 *buf = (ABuffer *)(item->u.refValue); 295 return true; 296 } 297 return false; 298 } 299 300 bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const { 301 const Item *item = findItem(name, kTypeMessage); 302 if (item) { 303 *obj = static_cast<AMessage *>(item->u.refValue); 304 return true; 305 } 306 return false; 307 } 308 309 bool AMessage::findRect( 310 const char *name, 311 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const { 312 const Item *item = findItem(name, kTypeRect); 313 if (item == NULL) { 314 return false; 315 } 316 317 *left = item->u.rectValue.mLeft; 318 *top = item->u.rectValue.mTop; 319 *right = item->u.rectValue.mRight; 320 *bottom = item->u.rectValue.mBottom; 321 322 return true; 323 } 324 325 void AMessage::post(int64_t delayUs) { 326 gLooperRoster.postMessage(this, delayUs); 327 } 328 329 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) { 330 return gLooperRoster.postAndAwaitResponse(this, response); 331 } 332 333 void AMessage::postReply(uint32_t replyID) { 334 gLooperRoster.postReply(replyID, this); 335 } 336 337 bool AMessage::senderAwaitsResponse(uint32_t *replyID) const { 338 int32_t tmp; 339 bool found = findInt32("replyID", &tmp); 340 341 if (!found) { 342 return false; 343 } 344 345 *replyID = static_cast<uint32_t>(tmp); 346 347 return true; 348 } 349 350 sp<AMessage> AMessage::dup() const { 351 sp<AMessage> msg = new AMessage(mWhat, mTarget); 352 msg->mNumItems = mNumItems; 353 354 #ifdef DUMP_STATS 355 { 356 Mutex::Autolock _l(gLock); 357 ++gDupCalls; 358 gAverageDupItems += mNumItems; 359 reportStats(); 360 } 361 #endif 362 363 for (size_t i = 0; i < mNumItems; ++i) { 364 const Item *from = &mItems[i]; 365 Item *to = &msg->mItems[i]; 366 367 to->setName(from->mName, from->mNameLength); 368 to->mType = from->mType; 369 370 switch (from->mType) { 371 case kTypeString: 372 { 373 to->u.stringValue = 374 new AString(*from->u.stringValue); 375 break; 376 } 377 378 case kTypeObject: 379 case kTypeBuffer: 380 { 381 to->u.refValue = from->u.refValue; 382 to->u.refValue->incStrong(msg.get()); 383 break; 384 } 385 386 case kTypeMessage: 387 { 388 sp<AMessage> copy = 389 static_cast<AMessage *>(from->u.refValue)->dup(); 390 391 to->u.refValue = copy.get(); 392 to->u.refValue->incStrong(msg.get()); 393 break; 394 } 395 396 default: 397 { 398 to->u = from->u; 399 break; 400 } 401 } 402 } 403 404 return msg; 405 } 406 407 static void appendIndent(AString *s, int32_t indent) { 408 static const char kWhitespace[] = 409 " " 410 " "; 411 412 CHECK_LT((size_t)indent, sizeof(kWhitespace)); 413 414 s->append(kWhitespace, indent); 415 } 416 417 static bool isFourcc(uint32_t what) { 418 return isprint(what & 0xff) 419 && isprint((what >> 8) & 0xff) 420 && isprint((what >> 16) & 0xff) 421 && isprint((what >> 24) & 0xff); 422 } 423 424 AString AMessage::debugString(int32_t indent) const { 425 AString s = "AMessage(what = "; 426 427 AString tmp; 428 if (isFourcc(mWhat)) { 429 tmp = StringPrintf( 430 "'%c%c%c%c'", 431 (char)(mWhat >> 24), 432 (char)((mWhat >> 16) & 0xff), 433 (char)((mWhat >> 8) & 0xff), 434 (char)(mWhat & 0xff)); 435 } else { 436 tmp = StringPrintf("0x%08x", mWhat); 437 } 438 s.append(tmp); 439 440 if (mTarget != 0) { 441 tmp = StringPrintf(", target = %d", mTarget); 442 s.append(tmp); 443 } 444 s.append(") = {\n"); 445 446 for (size_t i = 0; i < mNumItems; ++i) { 447 const Item &item = mItems[i]; 448 449 switch (item.mType) { 450 case kTypeInt32: 451 tmp = StringPrintf( 452 "int32_t %s = %d", item.mName, item.u.int32Value); 453 break; 454 case kTypeInt64: 455 tmp = StringPrintf( 456 "int64_t %s = %lld", item.mName, item.u.int64Value); 457 break; 458 case kTypeSize: 459 tmp = StringPrintf( 460 "size_t %s = %d", item.mName, item.u.sizeValue); 461 break; 462 case kTypeFloat: 463 tmp = StringPrintf( 464 "float %s = %f", item.mName, item.u.floatValue); 465 break; 466 case kTypeDouble: 467 tmp = StringPrintf( 468 "double %s = %f", item.mName, item.u.doubleValue); 469 break; 470 case kTypePointer: 471 tmp = StringPrintf( 472 "void *%s = %p", item.mName, item.u.ptrValue); 473 break; 474 case kTypeString: 475 tmp = StringPrintf( 476 "string %s = \"%s\"", 477 item.mName, 478 item.u.stringValue->c_str()); 479 break; 480 case kTypeObject: 481 tmp = StringPrintf( 482 "RefBase *%s = %p", item.mName, item.u.refValue); 483 break; 484 case kTypeBuffer: 485 { 486 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue); 487 488 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) { 489 tmp = StringPrintf("Buffer %s = {\n", item.mName); 490 hexdump(buffer->data(), buffer->size(), indent + 4, &tmp); 491 appendIndent(&tmp, indent + 2); 492 tmp.append("}"); 493 } else { 494 tmp = StringPrintf( 495 "Buffer *%s = %p", item.mName, buffer.get()); 496 } 497 break; 498 } 499 case kTypeMessage: 500 tmp = StringPrintf( 501 "AMessage %s = %s", 502 item.mName, 503 static_cast<AMessage *>( 504 item.u.refValue)->debugString( 505 indent + strlen(item.mName) + 14).c_str()); 506 break; 507 case kTypeRect: 508 tmp = StringPrintf( 509 "Rect %s(%d, %d, %d, %d)", 510 item.mName, 511 item.u.rectValue.mLeft, 512 item.u.rectValue.mTop, 513 item.u.rectValue.mRight, 514 item.u.rectValue.mBottom); 515 break; 516 default: 517 TRESPASS(); 518 } 519 520 appendIndent(&s, indent); 521 s.append(" "); 522 s.append(tmp); 523 s.append("\n"); 524 } 525 526 appendIndent(&s, indent); 527 s.append("}"); 528 529 return s; 530 } 531 532 // static 533 sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { 534 int32_t what = parcel.readInt32(); 535 sp<AMessage> msg = new AMessage(what); 536 537 msg->mNumItems = static_cast<size_t>(parcel.readInt32()); 538 for (size_t i = 0; i < msg->mNumItems; ++i) { 539 Item *item = &msg->mItems[i]; 540 541 const char *name = parcel.readCString(); 542 item->setName(name, strlen(name)); 543 item->mType = static_cast<Type>(parcel.readInt32()); 544 545 switch (item->mType) { 546 case kTypeInt32: 547 { 548 item->u.int32Value = parcel.readInt32(); 549 break; 550 } 551 552 case kTypeInt64: 553 { 554 item->u.int64Value = parcel.readInt64(); 555 break; 556 } 557 558 case kTypeSize: 559 { 560 item->u.sizeValue = static_cast<size_t>(parcel.readInt32()); 561 break; 562 } 563 564 case kTypeFloat: 565 { 566 item->u.floatValue = parcel.readFloat(); 567 break; 568 } 569 570 case kTypeDouble: 571 { 572 item->u.doubleValue = parcel.readDouble(); 573 break; 574 } 575 576 case kTypeString: 577 { 578 item->u.stringValue = new AString(parcel.readCString()); 579 break; 580 } 581 582 case kTypeMessage: 583 { 584 sp<AMessage> subMsg = AMessage::FromParcel(parcel); 585 subMsg->incStrong(msg.get()); 586 587 item->u.refValue = subMsg.get(); 588 break; 589 } 590 591 default: 592 { 593 ALOGE("This type of object cannot cross process boundaries."); 594 TRESPASS(); 595 } 596 } 597 } 598 599 return msg; 600 } 601 602 void AMessage::writeToParcel(Parcel *parcel) const { 603 parcel->writeInt32(static_cast<int32_t>(mWhat)); 604 parcel->writeInt32(static_cast<int32_t>(mNumItems)); 605 606 for (size_t i = 0; i < mNumItems; ++i) { 607 const Item &item = mItems[i]; 608 609 parcel->writeCString(item.mName); 610 parcel->writeInt32(static_cast<int32_t>(item.mType)); 611 612 switch (item.mType) { 613 case kTypeInt32: 614 { 615 parcel->writeInt32(item.u.int32Value); 616 break; 617 } 618 619 case kTypeInt64: 620 { 621 parcel->writeInt64(item.u.int64Value); 622 break; 623 } 624 625 case kTypeSize: 626 { 627 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue)); 628 break; 629 } 630 631 case kTypeFloat: 632 { 633 parcel->writeFloat(item.u.floatValue); 634 break; 635 } 636 637 case kTypeDouble: 638 { 639 parcel->writeDouble(item.u.doubleValue); 640 break; 641 } 642 643 case kTypeString: 644 { 645 parcel->writeCString(item.u.stringValue->c_str()); 646 break; 647 } 648 649 case kTypeMessage: 650 { 651 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel); 652 break; 653 } 654 655 default: 656 { 657 ALOGE("This type of object cannot cross process boundaries."); 658 TRESPASS(); 659 } 660 } 661 } 662 } 663 664 size_t AMessage::countEntries() const { 665 return mNumItems; 666 } 667 668 const char *AMessage::getEntryNameAt(size_t index, Type *type) const { 669 if (index >= mNumItems) { 670 *type = kTypeInt32; 671 672 return NULL; 673 } 674 675 *type = mItems[index].mType; 676 677 return mItems[index].mName; 678 } 679 680 } // namespace android 681