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