AMessage.cpp revision 5804a76ac5f9f3c311f1bbbcc5ebdc8f8568ae14
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 40AMessage::AMessage(void) 41 : mWhat(0), 42 mTarget(0), 43 mNumItems(0) { 44} 45 46AMessage::AMessage(uint32_t what, ALooper::handler_id target) 47 : mWhat(what), 48 mTarget(0), 49 mNumItems(0) { 50 setTarget(target); 51} 52 53AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler) 54 : mWhat(what), 55 mNumItems(0) { 56 setTarget(handler); 57} 58 59AMessage::~AMessage() { 60 clear(); 61} 62 63void AMessage::setWhat(uint32_t what) { 64 mWhat = what; 65} 66 67uint32_t AMessage::what() const { 68 return mWhat; 69} 70 71void AMessage::setTarget(ALooper::handler_id handlerID) { 72 mTarget = handlerID; 73 gLooperRoster.getHandlerAndLooper(handlerID, &mHandler, &mLooper); 74} 75 76void AMessage::setTarget(const sp<const AHandler> &handler) { 77 if (handler == NULL) { 78 mTarget = 0; 79 mHandler.clear(); 80 mLooper.clear(); 81 } else { 82 mTarget = handler->id(); 83 mHandler = handler->getHandler(); 84 mLooper = handler->getLooper(); 85 } 86} 87 88void AMessage::clear() { 89 for (size_t i = 0; i < mNumItems; ++i) { 90 Item *item = &mItems[i]; 91 delete[] item->mName; 92 item->mName = NULL; 93 freeItemValue(item); 94 } 95 mNumItems = 0; 96} 97 98void AMessage::freeItemValue(Item *item) { 99 switch (item->mType) { 100 case kTypeString: 101 { 102 delete item->u.stringValue; 103 break; 104 } 105 106 case kTypeObject: 107 case kTypeMessage: 108 case kTypeBuffer: 109 { 110 if (item->u.refValue != NULL) { 111 item->u.refValue->decStrong(this); 112 } 113 break; 114 } 115 116 default: 117 break; 118 } 119} 120 121#ifdef DUMP_STATS 122#include <utils/Mutex.h> 123 124Mutex gLock; 125static int32_t gFindItemCalls = 1; 126static int32_t gDupCalls = 1; 127static int32_t gAverageNumItems = 0; 128static int32_t gAverageNumChecks = 0; 129static int32_t gAverageNumMemChecks = 0; 130static int32_t gAverageDupItems = 0; 131static int32_t gLastChecked = -1; 132 133static void reportStats() { 134 int32_t time = (ALooper::GetNowUs() / 1000); 135 if (time / 1000 != gLastChecked / 1000) { 136 gLastChecked = time; 137 ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)", 138 gFindItemCalls, 139 gAverageNumItems / (float)gFindItemCalls, 140 gAverageNumChecks / (float)gFindItemCalls, 141 gAverageNumMemChecks / (float)gFindItemCalls, 142 gDupCalls, 143 gAverageDupItems / (float)gDupCalls); 144 gFindItemCalls = gDupCalls = 1; 145 gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0; 146 gLastChecked = time; 147 } 148} 149#endif 150 151inline size_t AMessage::findItemIndex(const char *name, size_t len) const { 152#ifdef DUMP_STATS 153 size_t memchecks = 0; 154#endif 155 size_t i = 0; 156 for (; i < mNumItems; i++) { 157 if (len != mItems[i].mNameLength) { 158 continue; 159 } 160#ifdef DUMP_STATS 161 ++memchecks; 162#endif 163 if (!memcmp(mItems[i].mName, name, len)) { 164 break; 165 } 166 } 167#ifdef DUMP_STATS 168 { 169 Mutex::Autolock _l(gLock); 170 ++gFindItemCalls; 171 gAverageNumItems += mNumItems; 172 gAverageNumMemChecks += memchecks; 173 gAverageNumChecks += i; 174 reportStats(); 175 } 176#endif 177 return i; 178} 179 180// assumes item's name was uninitialized or NULL 181void AMessage::Item::setName(const char *name, size_t len) { 182 mNameLength = len; 183 mName = new char[len + 1]; 184 memcpy((void*)mName, name, len + 1); 185} 186 187AMessage::Item *AMessage::allocateItem(const char *name) { 188 size_t len = strlen(name); 189 size_t i = findItemIndex(name, len); 190 Item *item; 191 192 if (i < mNumItems) { 193 item = &mItems[i]; 194 freeItemValue(item); 195 } else { 196 CHECK(mNumItems < kMaxNumItems); 197 i = mNumItems++; 198 item = &mItems[i]; 199 item->setName(name, len); 200 } 201 202 return item; 203} 204 205const AMessage::Item *AMessage::findItem( 206 const char *name, Type type) const { 207 size_t i = findItemIndex(name, strlen(name)); 208 if (i < mNumItems) { 209 const Item *item = &mItems[i]; 210 return item->mType == type ? item : NULL; 211 212 } 213 return NULL; 214} 215 216bool AMessage::contains(const char *name) const { 217 size_t i = findItemIndex(name, strlen(name)); 218 return i < mNumItems; 219} 220 221#define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \ 222void AMessage::set##NAME(const char *name, TYPENAME value) { \ 223 Item *item = allocateItem(name); \ 224 \ 225 item->mType = kType##NAME; \ 226 item->u.FIELDNAME = value; \ 227} \ 228 \ 229bool AMessage::find##NAME(const char *name, TYPENAME *value) const { \ 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 return gLooperRoster.postAndAwaitResponse(this, response); 371} 372 373void AMessage::postReply(uint32_t replyID) { 374 gLooperRoster.postReply(replyID, this); 375} 376 377bool AMessage::senderAwaitsResponse(uint32_t *replyID) const { 378 int32_t tmp; 379 bool found = findInt32("replyID", &tmp); 380 381 if (!found) { 382 return false; 383 } 384 385 *replyID = static_cast<uint32_t>(tmp); 386 387 return true; 388} 389 390sp<AMessage> AMessage::dup() const { 391 sp<AMessage> msg = new AMessage(mWhat, mHandler.promote()); 392 msg->mNumItems = mNumItems; 393 394#ifdef DUMP_STATS 395 { 396 Mutex::Autolock _l(gLock); 397 ++gDupCalls; 398 gAverageDupItems += mNumItems; 399 reportStats(); 400 } 401#endif 402 403 for (size_t i = 0; i < mNumItems; ++i) { 404 const Item *from = &mItems[i]; 405 Item *to = &msg->mItems[i]; 406 407 to->setName(from->mName, from->mNameLength); 408 to->mType = from->mType; 409 410 switch (from->mType) { 411 case kTypeString: 412 { 413 to->u.stringValue = 414 new AString(*from->u.stringValue); 415 break; 416 } 417 418 case kTypeObject: 419 case kTypeBuffer: 420 { 421 to->u.refValue = from->u.refValue; 422 to->u.refValue->incStrong(msg.get()); 423 break; 424 } 425 426 case kTypeMessage: 427 { 428 sp<AMessage> copy = 429 static_cast<AMessage *>(from->u.refValue)->dup(); 430 431 to->u.refValue = copy.get(); 432 to->u.refValue->incStrong(msg.get()); 433 break; 434 } 435 436 default: 437 { 438 to->u = from->u; 439 break; 440 } 441 } 442 } 443 444 return msg; 445} 446 447static void appendIndent(AString *s, int32_t indent) { 448 static const char kWhitespace[] = 449 " " 450 " "; 451 452 CHECK_LT((size_t)indent, sizeof(kWhitespace)); 453 454 s->append(kWhitespace, indent); 455} 456 457static bool isFourcc(uint32_t what) { 458 return isprint(what & 0xff) 459 && isprint((what >> 8) & 0xff) 460 && isprint((what >> 16) & 0xff) 461 && isprint((what >> 24) & 0xff); 462} 463 464AString AMessage::debugString(int32_t indent) const { 465 AString s = "AMessage(what = "; 466 467 AString tmp; 468 if (isFourcc(mWhat)) { 469 tmp = AStringPrintf( 470 "'%c%c%c%c'", 471 (char)(mWhat >> 24), 472 (char)((mWhat >> 16) & 0xff), 473 (char)((mWhat >> 8) & 0xff), 474 (char)(mWhat & 0xff)); 475 } else { 476 tmp = AStringPrintf("0x%08x", mWhat); 477 } 478 s.append(tmp); 479 480 if (mTarget != 0) { 481 tmp = AStringPrintf(", target = %d", mTarget); 482 s.append(tmp); 483 } 484 s.append(") = {\n"); 485 486 for (size_t i = 0; i < mNumItems; ++i) { 487 const Item &item = mItems[i]; 488 489 switch (item.mType) { 490 case kTypeInt32: 491 tmp = AStringPrintf( 492 "int32_t %s = %d", item.mName, item.u.int32Value); 493 break; 494 case kTypeInt64: 495 tmp = AStringPrintf( 496 "int64_t %s = %lld", item.mName, item.u.int64Value); 497 break; 498 case kTypeSize: 499 tmp = AStringPrintf( 500 "size_t %s = %d", item.mName, item.u.sizeValue); 501 break; 502 case kTypeFloat: 503 tmp = AStringPrintf( 504 "float %s = %f", item.mName, item.u.floatValue); 505 break; 506 case kTypeDouble: 507 tmp = AStringPrintf( 508 "double %s = %f", item.mName, item.u.doubleValue); 509 break; 510 case kTypePointer: 511 tmp = AStringPrintf( 512 "void *%s = %p", item.mName, item.u.ptrValue); 513 break; 514 case kTypeString: 515 tmp = AStringPrintf( 516 "string %s = \"%s\"", 517 item.mName, 518 item.u.stringValue->c_str()); 519 break; 520 case kTypeObject: 521 tmp = AStringPrintf( 522 "RefBase *%s = %p", item.mName, item.u.refValue); 523 break; 524 case kTypeBuffer: 525 { 526 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue); 527 528 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) { 529 tmp = AStringPrintf("Buffer %s = {\n", item.mName); 530 hexdump(buffer->data(), buffer->size(), indent + 4, &tmp); 531 appendIndent(&tmp, indent + 2); 532 tmp.append("}"); 533 } else { 534 tmp = AStringPrintf( 535 "Buffer *%s = %p", item.mName, buffer.get()); 536 } 537 break; 538 } 539 case kTypeMessage: 540 tmp = AStringPrintf( 541 "AMessage %s = %s", 542 item.mName, 543 static_cast<AMessage *>( 544 item.u.refValue)->debugString( 545 indent + strlen(item.mName) + 14).c_str()); 546 break; 547 case kTypeRect: 548 tmp = AStringPrintf( 549 "Rect %s(%d, %d, %d, %d)", 550 item.mName, 551 item.u.rectValue.mLeft, 552 item.u.rectValue.mTop, 553 item.u.rectValue.mRight, 554 item.u.rectValue.mBottom); 555 break; 556 default: 557 TRESPASS(); 558 } 559 560 appendIndent(&s, indent); 561 s.append(" "); 562 s.append(tmp); 563 s.append("\n"); 564 } 565 566 appendIndent(&s, indent); 567 s.append("}"); 568 569 return s; 570} 571 572// static 573sp<AMessage> AMessage::FromParcel(const Parcel &parcel) { 574 int32_t what = parcel.readInt32(); 575 sp<AMessage> msg = new AMessage(); 576 msg->setWhat(what); 577 578 msg->mNumItems = static_cast<size_t>(parcel.readInt32()); 579 for (size_t i = 0; i < msg->mNumItems; ++i) { 580 Item *item = &msg->mItems[i]; 581 582 const char *name = parcel.readCString(); 583 item->setName(name, strlen(name)); 584 item->mType = static_cast<Type>(parcel.readInt32()); 585 586 switch (item->mType) { 587 case kTypeInt32: 588 { 589 item->u.int32Value = parcel.readInt32(); 590 break; 591 } 592 593 case kTypeInt64: 594 { 595 item->u.int64Value = parcel.readInt64(); 596 break; 597 } 598 599 case kTypeSize: 600 { 601 item->u.sizeValue = static_cast<size_t>(parcel.readInt32()); 602 break; 603 } 604 605 case kTypeFloat: 606 { 607 item->u.floatValue = parcel.readFloat(); 608 break; 609 } 610 611 case kTypeDouble: 612 { 613 item->u.doubleValue = parcel.readDouble(); 614 break; 615 } 616 617 case kTypeString: 618 { 619 item->u.stringValue = new AString(parcel.readCString()); 620 break; 621 } 622 623 case kTypeMessage: 624 { 625 sp<AMessage> subMsg = AMessage::FromParcel(parcel); 626 subMsg->incStrong(msg.get()); 627 628 item->u.refValue = subMsg.get(); 629 break; 630 } 631 632 default: 633 { 634 ALOGE("This type of object cannot cross process boundaries."); 635 TRESPASS(); 636 } 637 } 638 } 639 640 return msg; 641} 642 643void AMessage::writeToParcel(Parcel *parcel) const { 644 parcel->writeInt32(static_cast<int32_t>(mWhat)); 645 parcel->writeInt32(static_cast<int32_t>(mNumItems)); 646 647 for (size_t i = 0; i < mNumItems; ++i) { 648 const Item &item = mItems[i]; 649 650 parcel->writeCString(item.mName); 651 parcel->writeInt32(static_cast<int32_t>(item.mType)); 652 653 switch (item.mType) { 654 case kTypeInt32: 655 { 656 parcel->writeInt32(item.u.int32Value); 657 break; 658 } 659 660 case kTypeInt64: 661 { 662 parcel->writeInt64(item.u.int64Value); 663 break; 664 } 665 666 case kTypeSize: 667 { 668 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue)); 669 break; 670 } 671 672 case kTypeFloat: 673 { 674 parcel->writeFloat(item.u.floatValue); 675 break; 676 } 677 678 case kTypeDouble: 679 { 680 parcel->writeDouble(item.u.doubleValue); 681 break; 682 } 683 684 case kTypeString: 685 { 686 parcel->writeCString(item.u.stringValue->c_str()); 687 break; 688 } 689 690 case kTypeMessage: 691 { 692 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel); 693 break; 694 } 695 696 default: 697 { 698 ALOGE("This type of object cannot cross process boundaries."); 699 TRESPASS(); 700 } 701 } 702 } 703} 704 705size_t AMessage::countEntries() const { 706 return mNumItems; 707} 708 709const char *AMessage::getEntryNameAt(size_t index, Type *type) const { 710 if (index >= mNumItems) { 711 *type = kTypeInt32; 712 713 return NULL; 714 } 715 716 *type = mItems[index].mType; 717 718 return mItems[index].mName; 719} 720 721} // namespace android 722