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