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