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