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