• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 namespace android {
38 
39 extern ALooperRoster gLooperRoster;
40 
setReply(const sp<AMessage> & reply)41 status_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 
AMessage(void)52 AMessage::AMessage(void)
53     : mWhat(0),
54       mTarget(0),
55       mNumItems(0) {
56 }
57 
AMessage(uint32_t what,const sp<const AHandler> & handler)58 AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
59     : mWhat(what),
60       mNumItems(0) {
61     setTarget(handler);
62 }
63 
~AMessage()64 AMessage::~AMessage() {
65     clear();
66 }
67 
setWhat(uint32_t what)68 void AMessage::setWhat(uint32_t what) {
69     mWhat = what;
70 }
71 
what() const72 uint32_t AMessage::what() const {
73     return mWhat;
74 }
75 
setTarget(const sp<const AHandler> & handler)76 void 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 
clear()88 void 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 
freeItemValue(Item * item)98 void 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 
124 Mutex gLock;
125 static int32_t gFindItemCalls = 1;
126 static int32_t gDupCalls = 1;
127 static int32_t gAverageNumItems = 0;
128 static int32_t gAverageNumChecks = 0;
129 static int32_t gAverageNumMemChecks = 0;
130 static int32_t gAverageDupItems = 0;
131 static int32_t gLastChecked = -1;
132 
reportStats()133 static 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 
findItemIndex(const char * name,size_t len) const151 inline 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
setName(const char * name,size_t len)181 void 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 
allocateItem(const char * name)187 AMessage::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 
findItem(const char * name,Type type) const205 const 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 
findAsFloat(const char * name,float * value) const216 bool 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 
findAsInt64(const char * name,int64_t * value) const243 bool 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 
contains(const char * name) const261 bool 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)                             \
267 void 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 */       \
275 bool 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 
BASIC_TYPE(Int32,int32Value,int32_t)284 BASIC_TYPE(Int32,int32Value,int32_t)
285 BASIC_TYPE(Int64,int64Value,int64_t)
286 BASIC_TYPE(Size,sizeValue,size_t)
287 BASIC_TYPE(Float,floatValue,float)
288 BASIC_TYPE(Double,doubleValue,double)
289 BASIC_TYPE(Pointer,ptrValue,void *)
290 
291 #undef BASIC_TYPE
292 
293 void 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 
setString(const char * name,const AString & s)300 void AMessage::setString(
301         const char *name, const AString &s) {
302     setString(name, s.c_str(), s.size());
303 }
304 
setObjectInternal(const char * name,const sp<RefBase> & obj,Type type)305 void 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 
setObject(const char * name,const sp<RefBase> & obj)314 void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
315     setObjectInternal(name, obj, kTypeObject);
316 }
317 
setBuffer(const char * name,const sp<ABuffer> & buffer)318 void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
319     setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
320 }
321 
setMessage(const char * name,const sp<AMessage> & obj)322 void 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 
setRect(const char * name,int32_t left,int32_t top,int32_t right,int32_t bottom)330 void 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 
findString(const char * name,AString * value) const342 bool 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 
findObject(const char * name,sp<RefBase> * obj) const351 bool 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 
findBuffer(const char * name,sp<ABuffer> * buf) const360 bool 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 
findMessage(const char * name,sp<AMessage> * obj) const369 bool 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 
findRect(const char * name,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const378 bool 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 
deliver()394 void 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 
post(int64_t delayUs)404 status_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 
postAndAwaitResponse(sp<AMessage> * response)415 status_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 
postReply(const sp<AReplyToken> & replyToken)433 status_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 
senderAwaitsResponse(sp<AReplyToken> * replyToken)446 bool 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 
dup() const462 sp<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 
appendIndent(AString * s,int32_t indent)519 static 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 
isFourcc(uint32_t what)529 static 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 
debugString(int32_t indent) const536 AString 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
FromParcel(const Parcel & parcel,size_t maxNestingLevel)645 sp<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 
writeToParcel(Parcel * parcel) const749 void 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 
changesFrom(const sp<const AMessage> & other,bool deep) const811 sp<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 
countEntries() const931 size_t AMessage::countEntries() const {
932     return mNumItems;
933 }
934 
getEntryNameAt(size_t index,Type * type) const935 const 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