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