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