AMessage.cpp revision 60d02077d86d2d1092443519290101f503aa6f7a
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 21#include <ctype.h> 22 23#include "AMessage.h" 24 25#include <android/log.h> 26#include <binder/Parcel.h> 27 28#include "AAtomizer.h" 29#include "ABuffer.h" 30#include "ADebug.h" 31#include "ALooperRoster.h" 32#include "AHandler.h" 33#include "AString.h" 34 35#include <media/stagefright/foundation/hexdump.h> 36 37namespace android { 38 39extern ALooperRoster gLooperRoster; 40 41status_t AReplyToken::setReply(const sp<AMessage> &reply) { 42 if (mReplied) { 43 ALOGE("trying to post a duplicate reply"); 44 return -EBUSY; 45 } 46 CHECK(mReply == NULL); 47 mReply = reply; 48 mReplied = true; 49 return OK; 50} 51 52AMessage::AMessage(void) 53 : mWhat(0), 54 mTarget(0), 55 mNumItems(0) { 56} 57 58AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler) 59 : mWhat(what), 60 mNumItems(0) { 61 setTarget(handler); 62} 63 64AMessage::~AMessage() { 65 clear(); 66} 67 68void AMessage::setWhat(uint32_t what) { 69 mWhat = what; 70} 71 72uint32_t AMessage::what() const { 73 return mWhat; 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::findAsFloat(const char *name, float *value) const { 217 size_t i = findItemIndex(name, strlen(name)); 218 if (i < mNumItems) { 219 const Item *item = &mItems[i]; 220 switch (item->mType) { 221 case kTypeFloat: 222 *value = item->u.floatValue; 223 return true; 224 case kTypeDouble: 225 *value = (float)item->u.doubleValue; 226 return true; 227 case kTypeInt64: 228 *value = (float)item->u.int64Value; 229 return true; 230 case kTypeInt32: 231 *value = (float)item->u.int32Value; 232 return true; 233 case kTypeSize: 234 *value = (float)item->u.sizeValue; 235 return true; 236 default: 237 return false; 238 } 239 } 240 return false; 241} 242 243bool AMessage::contains(const char *name) const { 244 size_t i = findItemIndex(name, strlen(name)); 245 return i < mNumItems; 246} 247 248#define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \ 249void AMessage::set##NAME(const char *name, TYPENAME value) { \ 250 Item *item = allocateItem(name); \ 251 \ 252 item->mType = kType##NAME; \ 253 item->u.FIELDNAME = value; \ 254} \ 255 \ 256/* NOLINT added to avoid incorrect warning/fix from clang.tidy */ \ 257bool AMessage::find##NAME(const char *name, TYPENAME *value) const { /* NOLINT */ \ 258 const Item *item = findItem(name, kType##NAME); \ 259 if (item) { \ 260 *value = item->u.FIELDNAME; \ 261 return true; \ 262 } \ 263 return false; \ 264} 265 266BASIC_TYPE(Int32,int32Value,int32_t) 267BASIC_TYPE(Int64,int64Value,int64_t) 268BASIC_TYPE(Size,sizeValue,size_t) 269BASIC_TYPE(Float,floatValue,float) 270BASIC_TYPE(Double,doubleValue,double) 271BASIC_TYPE(Pointer,ptrValue,void *) 272 273#undef BASIC_TYPE 274 275void AMessage::setString( 276 const char *name, const char *s, ssize_t len) { 277 Item *item = allocateItem(name); 278 item->mType = kTypeString; 279 item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len); 280} 281 282void AMessage::setString( 283 const char *name, const AString &s) { 284 setString(name, s.c_str(), s.size()); 285} 286 287void AMessage::setObjectInternal( 288 const char *name, const sp<RefBase> &obj, Type type) { 289 Item *item = allocateItem(name); 290 item->mType = type; 291 292 if (obj != NULL) { obj->incStrong(this); } 293 item->u.refValue = obj.get(); 294} 295 296void AMessage::setObject(const char *name, const sp<RefBase> &obj) { 297 setObjectInternal(name, obj, kTypeObject); 298} 299 300void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) { 301 setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer); 302} 303 304void AMessage::setMessage(const char *name, const sp<AMessage> &obj) { 305 Item *item = allocateItem(name); 306 item->mType = kTypeMessage; 307 308 if (obj != NULL) { obj->incStrong(this); } 309 item->u.refValue = obj.get(); 310} 311 312void AMessage::setRect( 313 const char *name, 314 int32_t left, int32_t top, int32_t right, int32_t bottom) { 315 Item *item = allocateItem(name); 316 item->mType = kTypeRect; 317 318 item->u.rectValue.mLeft = left; 319 item->u.rectValue.mTop = top; 320 item->u.rectValue.mRight = right; 321 item->u.rectValue.mBottom = bottom; 322} 323 324bool AMessage::findString(const char *name, AString *value) const { 325 const Item *item = findItem(name, kTypeString); 326 if (item) { 327 *value = *item->u.stringValue; 328 return true; 329 } 330 return false; 331} 332 333bool AMessage::findObject(const char *name, sp<RefBase> *obj) const { 334 const Item *item = findItem(name, kTypeObject); 335 if (item) { 336 *obj = item->u.refValue; 337 return true; 338 } 339 return false; 340} 341 342bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const { 343 const Item *item = findItem(name, kTypeBuffer); 344 if (item) { 345 *buf = (ABuffer *)(item->u.refValue); 346 return true; 347 } 348 return false; 349} 350 351bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const { 352 const Item *item = findItem(name, kTypeMessage); 353 if (item) { 354 *obj = static_cast<AMessage *>(item->u.refValue); 355 return true; 356 } 357 return false; 358} 359 360bool AMessage::findRect( 361 const char *name, 362 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const { 363 const Item *item = findItem(name, kTypeRect); 364 if (item == NULL) { 365 return false; 366 } 367 368 *left = item->u.rectValue.mLeft; 369 *top = item->u.rectValue.mTop; 370 *right = item->u.rectValue.mRight; 371 *bottom = item->u.rectValue.mBottom; 372 373 return true; 374} 375 376void AMessage::deliver() { 377 sp<AHandler> handler = mHandler.promote(); 378 if (handler == NULL) { 379 ALOGW("failed to deliver message as target handler %d is gone.", mTarget); 380 return; 381 } 382 383 handler->deliverMessage(this); 384} 385 386status_t AMessage::post(int64_t delayUs) { 387 sp<ALooper> looper = mLooper.promote(); 388 if (looper == NULL) { 389 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget); 390 return -ENOENT; 391 } 392 393 looper->post(this, delayUs); 394 return OK; 395} 396 397status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) { 398 sp<ALooper> looper = mLooper.promote(); 399 if (looper == NULL) { 400 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget); 401 return -ENOENT; 402 } 403 404 sp<AReplyToken> token = looper->createReplyToken(); 405 if (token == NULL) { 406 ALOGE("failed to create reply token"); 407 return -ENOMEM; 408 } 409 setObject("replyID", token); 410 411 looper->post(this, 0 /* delayUs */); 412 return looper->awaitResponse(token, response); 413} 414 415status_t AMessage::postReply(const sp<AReplyToken> &replyToken) { 416 if (replyToken == NULL) { 417 ALOGW("failed to post reply to a NULL token"); 418 return -ENOENT; 419 } 420 sp<ALooper> looper = replyToken->getLooper(); 421 if (looper == NULL) { 422 ALOGW("failed to post reply as target looper is gone."); 423 return -ENOENT; 424 } 425 return looper->postReply(replyToken, this); 426} 427 428bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) { 429 sp<RefBase> tmp; 430 bool found = findObject("replyID", &tmp); 431 432 if (!found) { 433 return false; 434 } 435 436 *replyToken = static_cast<AReplyToken *>(tmp.get()); 437 tmp.clear(); 438 setObject("replyID", tmp); 439 // TODO: delete Object instead of setting it to NULL 440 441 return *replyToken != NULL; 442} 443 444sp<AMessage> AMessage::dup() const { 445 sp<AMessage> msg = new AMessage(mWhat, mHandler.promote()); 446 msg->mNumItems = mNumItems; 447 448#ifdef DUMP_STATS 449 { 450 Mutex::Autolock _l(gLock); 451 ++gDupCalls; 452 gAverageDupItems += mNumItems; 453 reportStats(); 454 } 455#endif 456 457 for (size_t i = 0; i < mNumItems; ++i) { 458 const Item *from = &mItems[i]; 459 Item *to = &msg->mItems[i]; 460 461 to->setName(from->mName, from->mNameLength); 462 to->mType = from->mType; 463 464 switch (from->mType) { 465 case kTypeString: 466 { 467 to->u.stringValue = 468 new AString(*from->u.stringValue); 469 break; 470 } 471 472 case kTypeObject: 473 case kTypeBuffer: 474 { 475 to->u.refValue = from->u.refValue; 476 to->u.refValue->incStrong(msg.get()); 477 break; 478 } 479 480 case kTypeMessage: 481 { 482 sp<AMessage> copy = 483 static_cast<AMessage *>(from->u.refValue)->dup(); 484 485 to->u.refValue = copy.get(); 486 to->u.refValue->incStrong(msg.get()); 487 break; 488 } 489 490 default: 491 { 492 to->u = from->u; 493 break; 494 } 495 } 496 } 497 498 return msg; 499} 500 501static void appendIndent(AString *s, int32_t indent) { 502 static const char kWhitespace[] = 503 " " 504 " "; 505 506 CHECK_LT((size_t)indent, sizeof(kWhitespace)); 507 508 s->append(kWhitespace, indent); 509} 510 511static bool isFourcc(uint32_t what) { 512 return isprint(what & 0xff) 513 && isprint((what >> 8) & 0xff) 514 && isprint((what >> 16) & 0xff) 515 && isprint((what >> 24) & 0xff); 516} 517 518AString AMessage::debugString(int32_t indent) const { 519 AString s = "AMessage(what = "; 520 521 AString tmp; 522 if (isFourcc(mWhat)) { 523 tmp = AStringPrintf( 524 "'%c%c%c%c'", 525 (char)(mWhat >> 24), 526 (char)((mWhat >> 16) & 0xff), 527 (char)((mWhat >> 8) & 0xff), 528 (char)(mWhat & 0xff)); 529 } else { 530 tmp = AStringPrintf("0x%08x", mWhat); 531 } 532 s.append(tmp); 533 534 if (mTarget != 0) { 535 tmp = AStringPrintf(", target = %d", mTarget); 536 s.append(tmp); 537 } 538 s.append(") = {\n"); 539 540 for (size_t i = 0; i < mNumItems; ++i) { 541 const Item &item = mItems[i]; 542 543 switch (item.mType) { 544 case kTypeInt32: 545 tmp = AStringPrintf( 546 "int32_t %s = %d", item.mName, item.u.int32Value); 547 break; 548 case kTypeInt64: 549 tmp = AStringPrintf( 550 "int64_t %s = %lld", item.mName, item.u.int64Value); 551 break; 552 case kTypeSize: 553 tmp = AStringPrintf( 554 "size_t %s = %d", item.mName, item.u.sizeValue); 555 break; 556 case kTypeFloat: 557 tmp = AStringPrintf( 558 "float %s = %f", item.mName, item.u.floatValue); 559 break; 560 case kTypeDouble: 561 tmp = AStringPrintf( 562 "double %s = %f", item.mName, item.u.doubleValue); 563 break; 564 case kTypePointer: 565 tmp = AStringPrintf( 566 "void *%s = %p", item.mName, item.u.ptrValue); 567 break; 568 case kTypeString: 569 tmp = AStringPrintf( 570 "string %s = \"%s\"", 571 item.mName, 572 item.u.stringValue->c_str()); 573 break; 574 case kTypeObject: 575 tmp = AStringPrintf( 576 "RefBase *%s = %p", item.mName, item.u.refValue); 577 break; 578 case kTypeBuffer: 579 { 580 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue); 581 582 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) { 583 tmp = AStringPrintf("Buffer %s = {\n", item.mName); 584 hexdump(buffer->data(), buffer->size(), indent + 4, &tmp); 585 appendIndent(&tmp, indent + 2); 586 tmp.append("}"); 587 } else { 588 tmp = AStringPrintf( 589 "Buffer *%s = %p", item.mName, buffer.get()); 590 } 591 break; 592 } 593 case kTypeMessage: 594 tmp = AStringPrintf( 595 "AMessage %s = %s", 596 item.mName, 597 static_cast<AMessage *>( 598 item.u.refValue)->debugString( 599 indent + strlen(item.mName) + 14).c_str()); 600 break; 601 case kTypeRect: 602 tmp = AStringPrintf( 603 "Rect %s(%d, %d, %d, %d)", 604 item.mName, 605 item.u.rectValue.mLeft, 606 item.u.rectValue.mTop, 607 item.u.rectValue.mRight, 608 item.u.rectValue.mBottom); 609 break; 610 default: 611 TRESPASS(); 612 } 613 614 appendIndent(&s, indent); 615 s.append(" "); 616 s.append(tmp); 617 s.append("\n"); 618 } 619 620 appendIndent(&s, indent); 621 s.append("}"); 622 623 return s; 624} 625 626// static 627sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) { 628 int32_t what = parcel.readInt32(); 629 sp<AMessage> msg = new AMessage(); 630 msg->setWhat(what); 631 632 msg->mNumItems = static_cast<size_t>(parcel.readInt32()); 633 if (msg->mNumItems > kMaxNumItems) { 634 ALOGE("Too large number of items clipped."); 635 msg->mNumItems = kMaxNumItems; 636 } 637 638 for (size_t i = 0; i < msg->mNumItems; ++i) { 639 Item *item = &msg->mItems[i]; 640 641 const char *name = parcel.readCString(); 642 if (name == NULL) { 643 ALOGE("Failed reading name for an item. Parsing aborted."); 644 msg->mNumItems = i; 645 break; 646 } 647 648 item->mType = static_cast<Type>(parcel.readInt32()); 649 // setName() happens below so that we don't leak memory when parsing 650 // is aborted in the middle. 651 switch (item->mType) { 652 case kTypeInt32: 653 { 654 item->u.int32Value = parcel.readInt32(); 655 break; 656 } 657 658 case kTypeInt64: 659 { 660 item->u.int64Value = parcel.readInt64(); 661 break; 662 } 663 664 case kTypeSize: 665 { 666 item->u.sizeValue = static_cast<size_t>(parcel.readInt32()); 667 break; 668 } 669 670 case kTypeFloat: 671 { 672 item->u.floatValue = parcel.readFloat(); 673 break; 674 } 675 676 case kTypeDouble: 677 { 678 item->u.doubleValue = parcel.readDouble(); 679 break; 680 } 681 682 case kTypeString: 683 { 684 const char *stringValue = parcel.readCString(); 685 if (stringValue == NULL) { 686 ALOGE("Failed reading string value from a parcel. " 687 "Parsing aborted."); 688 msg->mNumItems = i; 689 continue; 690 // The loop will terminate subsequently. 691 } else { 692 item->u.stringValue = new AString(stringValue); 693 } 694 break; 695 } 696 697 case kTypeMessage: 698 { 699 if (maxNestingLevel == 0) { 700 ALOGE("Too many levels of AMessage nesting."); 701 return NULL; 702 } 703 sp<AMessage> subMsg = AMessage::FromParcel( 704 parcel, 705 maxNestingLevel - 1); 706 if (subMsg == NULL) { 707 // This condition will be triggered when there exists an 708 // object that cannot cross process boundaries or when the 709 // level of nested AMessage is too deep. 710 return NULL; 711 } 712 subMsg->incStrong(msg.get()); 713 714 item->u.refValue = subMsg.get(); 715 break; 716 } 717 718 default: 719 { 720 ALOGE("This type of object cannot cross process boundaries."); 721 return NULL; 722 } 723 } 724 725 item->setName(name, strlen(name)); 726 } 727 728 return msg; 729} 730 731void AMessage::writeToParcel(Parcel *parcel) const { 732 parcel->writeInt32(static_cast<int32_t>(mWhat)); 733 parcel->writeInt32(static_cast<int32_t>(mNumItems)); 734 735 for (size_t i = 0; i < mNumItems; ++i) { 736 const Item &item = mItems[i]; 737 738 parcel->writeCString(item.mName); 739 parcel->writeInt32(static_cast<int32_t>(item.mType)); 740 741 switch (item.mType) { 742 case kTypeInt32: 743 { 744 parcel->writeInt32(item.u.int32Value); 745 break; 746 } 747 748 case kTypeInt64: 749 { 750 parcel->writeInt64(item.u.int64Value); 751 break; 752 } 753 754 case kTypeSize: 755 { 756 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue)); 757 break; 758 } 759 760 case kTypeFloat: 761 { 762 parcel->writeFloat(item.u.floatValue); 763 break; 764 } 765 766 case kTypeDouble: 767 { 768 parcel->writeDouble(item.u.doubleValue); 769 break; 770 } 771 772 case kTypeString: 773 { 774 parcel->writeCString(item.u.stringValue->c_str()); 775 break; 776 } 777 778 case kTypeMessage: 779 { 780 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel); 781 break; 782 } 783 784 default: 785 { 786 ALOGE("This type of object cannot cross process boundaries."); 787 TRESPASS(); 788 } 789 } 790 } 791} 792 793sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const { 794 if (other == NULL) { 795 return const_cast<AMessage*>(this); 796 } 797 798 sp<AMessage> diff = new AMessage; 799 if (mWhat != other->mWhat) { 800 diff->setWhat(mWhat); 801 } 802 if (mHandler != other->mHandler) { 803 diff->setTarget(mHandler.promote()); 804 } 805 806 for (size_t i = 0; i < mNumItems; ++i) { 807 const Item &item = mItems[i]; 808 const Item *oitem = other->findItem(item.mName, item.mType); 809 switch (item.mType) { 810 case kTypeInt32: 811 if (oitem == NULL || item.u.int32Value != oitem->u.int32Value) { 812 diff->setInt32(item.mName, item.u.int32Value); 813 } 814 break; 815 816 case kTypeInt64: 817 if (oitem == NULL || item.u.int64Value != oitem->u.int64Value) { 818 diff->setInt64(item.mName, item.u.int64Value); 819 } 820 break; 821 822 case kTypeSize: 823 if (oitem == NULL || item.u.sizeValue != oitem->u.sizeValue) { 824 diff->setSize(item.mName, item.u.sizeValue); 825 } 826 break; 827 828 case kTypeFloat: 829 if (oitem == NULL || item.u.floatValue != oitem->u.floatValue) { 830 diff->setFloat(item.mName, item.u.sizeValue); 831 } 832 break; 833 834 case kTypeDouble: 835 if (oitem == NULL || item.u.doubleValue != oitem->u.doubleValue) { 836 diff->setDouble(item.mName, item.u.sizeValue); 837 } 838 break; 839 840 case kTypeString: 841 if (oitem == NULL || *item.u.stringValue != *oitem->u.stringValue) { 842 diff->setString(item.mName, *item.u.stringValue); 843 } 844 break; 845 846 case kTypeRect: 847 if (oitem == NULL || memcmp(&item.u.rectValue, &oitem->u.rectValue, sizeof(Rect))) { 848 diff->setRect( 849 item.mName, item.u.rectValue.mLeft, item.u.rectValue.mTop, 850 item.u.rectValue.mRight, item.u.rectValue.mBottom); 851 } 852 break; 853 854 case kTypePointer: 855 if (oitem == NULL || item.u.ptrValue != oitem->u.ptrValue) { 856 diff->setPointer(item.mName, item.u.ptrValue); 857 } 858 break; 859 860 case kTypeBuffer: 861 { 862 sp<ABuffer> myBuf = static_cast<ABuffer *>(item.u.refValue); 863 if (myBuf == NULL) { 864 if (oitem == NULL || oitem->u.refValue != NULL) { 865 diff->setBuffer(item.mName, NULL); 866 } 867 break; 868 } 869 sp<ABuffer> oBuf = oitem == NULL ? NULL : static_cast<ABuffer *>(oitem->u.refValue); 870 if (oBuf == NULL 871 || myBuf->size() != oBuf->size() 872 || (!myBuf->data() ^ !oBuf->data()) // data nullness differs 873 || (myBuf->data() && memcmp(myBuf->data(), oBuf->data(), myBuf->size()))) { 874 diff->setBuffer(item.mName, myBuf); 875 } 876 break; 877 } 878 879 case kTypeMessage: 880 { 881 sp<AMessage> myMsg = static_cast<AMessage *>(item.u.refValue); 882 if (myMsg == NULL) { 883 if (oitem == NULL || oitem->u.refValue != NULL) { 884 diff->setMessage(item.mName, NULL); 885 } 886 break; 887 } 888 sp<AMessage> oMsg = 889 oitem == NULL ? NULL : static_cast<AMessage *>(oitem->u.refValue); 890 sp<AMessage> changes = myMsg->changesFrom(oMsg, deep); 891 if (changes->countEntries()) { 892 diff->setMessage(item.mName, deep ? changes : myMsg); 893 } 894 break; 895 } 896 897 case kTypeObject: 898 if (oitem == NULL || item.u.refValue != oitem->u.refValue) { 899 diff->setObject(item.mName, item.u.refValue); 900 } 901 break; 902 903 default: 904 { 905 ALOGE("Unknown type %d", item.mType); 906 TRESPASS(); 907 } 908 } 909 } 910 return diff; 911} 912 913size_t AMessage::countEntries() const { 914 return mNumItems; 915} 916 917const char *AMessage::getEntryNameAt(size_t index, Type *type) const { 918 if (index >= mNumItems) { 919 *type = kTypeInt32; 920 921 return NULL; 922 } 923 924 *type = mItems[index].mType; 925 926 return mItems[index].mName; 927} 928 929} // namespace android 930