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 <log/log.h>
26 
27 #include "AAtomizer.h"
28 #include "ABuffer.h"
29 #include "ADebug.h"
30 #include "ALooperRoster.h"
31 #include "AHandler.h"
32 #include "AString.h"
33 
34 #include <media/stagefright/foundation/hexdump.h>
35 
36 #ifndef __ANDROID_VNDK__
37 #include <binder/Parcel.h>
38 #endif
39 
40 namespace android {
41 
42 extern ALooperRoster gLooperRoster;
43 
setReply(const sp<AMessage> & reply)44 status_t AReplyToken::setReply(const sp<AMessage> &reply) {
45     if (mReplied) {
46         ALOGE("trying to post a duplicate reply");
47         return -EBUSY;
48     }
49     CHECK(mReply == NULL);
50     mReply = reply;
51     mReplied = true;
52     return OK;
53 }
54 
AMessage(void)55 AMessage::AMessage(void)
56     : mWhat(0),
57       mTarget(0),
58       mNumItems(0) {
59 }
60 
AMessage(uint32_t what,const sp<const AHandler> & handler)61 AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
62     : mWhat(what),
63       mNumItems(0) {
64     setTarget(handler);
65 }
66 
~AMessage()67 AMessage::~AMessage() {
68     clear();
69 }
70 
setWhat(uint32_t what)71 void AMessage::setWhat(uint32_t what) {
72     mWhat = what;
73 }
74 
what() const75 uint32_t AMessage::what() const {
76     return mWhat;
77 }
78 
setTarget(const sp<const AHandler> & handler)79 void AMessage::setTarget(const sp<const AHandler> &handler) {
80     if (handler == NULL) {
81         mTarget = 0;
82         mHandler.clear();
83         mLooper.clear();
84     } else {
85         mTarget = handler->id();
86         mHandler = handler->getHandler();
87         mLooper = handler->getLooper();
88     }
89 }
90 
clear()91 void AMessage::clear() {
92     for (size_t i = 0; i < mNumItems; ++i) {
93         Item *item = &mItems[i];
94         delete[] item->mName;
95         item->mName = NULL;
96         freeItemValue(item);
97     }
98     mNumItems = 0;
99 }
100 
freeItemValue(Item * item)101 void AMessage::freeItemValue(Item *item) {
102     switch (item->mType) {
103         case kTypeString:
104         {
105             delete item->u.stringValue;
106             break;
107         }
108 
109         case kTypeObject:
110         case kTypeMessage:
111         case kTypeBuffer:
112         {
113             if (item->u.refValue != NULL) {
114                 item->u.refValue->decStrong(this);
115             }
116             break;
117         }
118 
119         default:
120             break;
121     }
122     item->mType = kTypeInt32; // clear type
123 }
124 
125 #ifdef DUMP_STATS
126 #include <utils/Mutex.h>
127 
128 Mutex gLock;
129 static int32_t gFindItemCalls = 1;
130 static int32_t gDupCalls = 1;
131 static int32_t gAverageNumItems = 0;
132 static int32_t gAverageNumChecks = 0;
133 static int32_t gAverageNumMemChecks = 0;
134 static int32_t gAverageDupItems = 0;
135 static int32_t gLastChecked = -1;
136 
reportStats()137 static void reportStats() {
138     int32_t time = (ALooper::GetNowUs() / 1000);
139     if (time / 1000 != gLastChecked / 1000) {
140         gLastChecked = time;
141         ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)",
142                 gFindItemCalls,
143                 gAverageNumItems / (float)gFindItemCalls,
144                 gAverageNumChecks / (float)gFindItemCalls,
145                 gAverageNumMemChecks / (float)gFindItemCalls,
146                 gDupCalls,
147                 gAverageDupItems / (float)gDupCalls);
148         gFindItemCalls = gDupCalls = 1;
149         gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0;
150         gLastChecked = time;
151     }
152 }
153 #endif
154 
findItemIndex(const char * name,size_t len) const155 inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
156 #ifdef DUMP_STATS
157     size_t memchecks = 0;
158 #endif
159     size_t i = 0;
160     for (; i < mNumItems; i++) {
161         if (len != mItems[i].mNameLength) {
162             continue;
163         }
164 #ifdef DUMP_STATS
165         ++memchecks;
166 #endif
167         if (!memcmp(mItems[i].mName, name, len)) {
168             break;
169         }
170     }
171 #ifdef DUMP_STATS
172     {
173         Mutex::Autolock _l(gLock);
174         ++gFindItemCalls;
175         gAverageNumItems += mNumItems;
176         gAverageNumMemChecks += memchecks;
177         gAverageNumChecks += i;
178         reportStats();
179     }
180 #endif
181     return i;
182 }
183 
184 // assumes item's name was uninitialized or NULL
setName(const char * name,size_t len)185 void AMessage::Item::setName(const char *name, size_t len) {
186     mNameLength = len;
187     mName = new char[len + 1];
188     memcpy((void*)mName, name, len + 1);
189 }
190 
allocateItem(const char * name)191 AMessage::Item *AMessage::allocateItem(const char *name) {
192     size_t len = strlen(name);
193     size_t i = findItemIndex(name, len);
194     Item *item;
195 
196     if (i < mNumItems) {
197         item = &mItems[i];
198         freeItemValue(item);
199     } else {
200         CHECK(mNumItems < kMaxNumItems);
201         i = mNumItems++;
202         item = &mItems[i];
203         item->mType = kTypeInt32;
204         item->setName(name, len);
205     }
206 
207     return item;
208 }
209 
findItem(const char * name,Type type) const210 const AMessage::Item *AMessage::findItem(
211         const char *name, Type type) const {
212     size_t i = findItemIndex(name, strlen(name));
213     if (i < mNumItems) {
214         const Item *item = &mItems[i];
215         return item->mType == type ? item : NULL;
216 
217     }
218     return NULL;
219 }
220 
findAsFloat(const char * name,float * value) const221 bool AMessage::findAsFloat(const char *name, float *value) const {
222     size_t i = findItemIndex(name, strlen(name));
223     if (i < mNumItems) {
224         const Item *item = &mItems[i];
225         switch (item->mType) {
226             case kTypeFloat:
227                 *value = item->u.floatValue;
228                 return true;
229             case kTypeDouble:
230                 *value = (float)item->u.doubleValue;
231                 return true;
232             case kTypeInt64:
233                 *value = (float)item->u.int64Value;
234                 return true;
235             case kTypeInt32:
236                 *value = (float)item->u.int32Value;
237                 return true;
238             case kTypeSize:
239                 *value = (float)item->u.sizeValue;
240                 return true;
241             default:
242                 return false;
243         }
244     }
245     return false;
246 }
247 
findAsInt64(const char * name,int64_t * value) const248 bool AMessage::findAsInt64(const char *name, int64_t *value) const {
249     size_t i = findItemIndex(name, strlen(name));
250     if (i < mNumItems) {
251         const Item *item = &mItems[i];
252         switch (item->mType) {
253             case kTypeInt64:
254                 *value = item->u.int64Value;
255                 return true;
256             case kTypeInt32:
257                 *value = item->u.int32Value;
258                 return true;
259             default:
260                 return false;
261         }
262     }
263     return false;
264 }
265 
contains(const char * name) const266 bool AMessage::contains(const char *name) const {
267     size_t i = findItemIndex(name, strlen(name));
268     return i < mNumItems;
269 }
270 
271 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME)                             \
272 void AMessage::set##NAME(const char *name, TYPENAME value) {            \
273     Item *item = allocateItem(name);                                    \
274                                                                         \
275     item->mType = kType##NAME;                                          \
276     item->u.FIELDNAME = value;                                          \
277 }                                                                       \
278                                                                         \
279 /* NOLINT added to avoid incorrect warning/fix from clang.tidy */       \
280 bool AMessage::find##NAME(const char *name, TYPENAME *value) const {  /* NOLINT */ \
281     const Item *item = findItem(name, kType##NAME);                     \
282     if (item) {                                                         \
283         *value = item->u.FIELDNAME;                                     \
284         return true;                                                    \
285     }                                                                   \
286     return false;                                                       \
287 }
288 
BASIC_TYPE(Int32,int32Value,int32_t)289 BASIC_TYPE(Int32,int32Value,int32_t)
290 BASIC_TYPE(Int64,int64Value,int64_t)
291 BASIC_TYPE(Size,sizeValue,size_t)
292 BASIC_TYPE(Float,floatValue,float)
293 BASIC_TYPE(Double,doubleValue,double)
294 BASIC_TYPE(Pointer,ptrValue,void *)
295 
296 #undef BASIC_TYPE
297 
298 void AMessage::setString(
299         const char *name, const char *s, ssize_t len) {
300     Item *item = allocateItem(name);
301     item->mType = kTypeString;
302     item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
303 }
304 
setString(const char * name,const AString & s)305 void AMessage::setString(
306         const char *name, const AString &s) {
307     setString(name, s.c_str(), s.size());
308 }
309 
setObjectInternal(const char * name,const sp<RefBase> & obj,Type type)310 void AMessage::setObjectInternal(
311         const char *name, const sp<RefBase> &obj, Type type) {
312     Item *item = allocateItem(name);
313     item->mType = type;
314 
315     if (obj != NULL) { obj->incStrong(this); }
316     item->u.refValue = obj.get();
317 }
318 
setObject(const char * name,const sp<RefBase> & obj)319 void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
320     setObjectInternal(name, obj, kTypeObject);
321 }
322 
setBuffer(const char * name,const sp<ABuffer> & buffer)323 void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
324     setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
325 }
326 
setMessage(const char * name,const sp<AMessage> & obj)327 void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
328     Item *item = allocateItem(name);
329     item->mType = kTypeMessage;
330 
331     if (obj != NULL) { obj->incStrong(this); }
332     item->u.refValue = obj.get();
333 }
334 
setRect(const char * name,int32_t left,int32_t top,int32_t right,int32_t bottom)335 void AMessage::setRect(
336         const char *name,
337         int32_t left, int32_t top, int32_t right, int32_t bottom) {
338     Item *item = allocateItem(name);
339     item->mType = kTypeRect;
340 
341     item->u.rectValue.mLeft = left;
342     item->u.rectValue.mTop = top;
343     item->u.rectValue.mRight = right;
344     item->u.rectValue.mBottom = bottom;
345 }
346 
findString(const char * name,AString * value) const347 bool AMessage::findString(const char *name, AString *value) const {
348     const Item *item = findItem(name, kTypeString);
349     if (item) {
350         *value = *item->u.stringValue;
351         return true;
352     }
353     return false;
354 }
355 
findObject(const char * name,sp<RefBase> * obj) const356 bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
357     const Item *item = findItem(name, kTypeObject);
358     if (item) {
359         *obj = item->u.refValue;
360         return true;
361     }
362     return false;
363 }
364 
findBuffer(const char * name,sp<ABuffer> * buf) const365 bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const {
366     const Item *item = findItem(name, kTypeBuffer);
367     if (item) {
368         *buf = (ABuffer *)(item->u.refValue);
369         return true;
370     }
371     return false;
372 }
373 
findMessage(const char * name,sp<AMessage> * obj) const374 bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
375     const Item *item = findItem(name, kTypeMessage);
376     if (item) {
377         *obj = static_cast<AMessage *>(item->u.refValue);
378         return true;
379     }
380     return false;
381 }
382 
findRect(const char * name,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const383 bool AMessage::findRect(
384         const char *name,
385         int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
386     const Item *item = findItem(name, kTypeRect);
387     if (item == NULL) {
388         return false;
389     }
390 
391     *left = item->u.rectValue.mLeft;
392     *top = item->u.rectValue.mTop;
393     *right = item->u.rectValue.mRight;
394     *bottom = item->u.rectValue.mBottom;
395 
396     return true;
397 }
398 
deliver()399 void AMessage::deliver() {
400     sp<AHandler> handler = mHandler.promote();
401     if (handler == NULL) {
402         ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
403         return;
404     }
405 
406     handler->deliverMessage(this);
407 }
408 
post(int64_t delayUs)409 status_t AMessage::post(int64_t delayUs) {
410     sp<ALooper> looper = mLooper.promote();
411     if (looper == NULL) {
412         ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
413         return -ENOENT;
414     }
415 
416     looper->post(this, delayUs);
417     return OK;
418 }
419 
postAndAwaitResponse(sp<AMessage> * response)420 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
421     sp<ALooper> looper = mLooper.promote();
422     if (looper == NULL) {
423         ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
424         return -ENOENT;
425     }
426 
427     sp<AReplyToken> token = looper->createReplyToken();
428     if (token == NULL) {
429         ALOGE("failed to create reply token");
430         return -ENOMEM;
431     }
432     setObject("replyID", token);
433 
434     looper->post(this, 0 /* delayUs */);
435     return looper->awaitResponse(token, response);
436 }
437 
postReply(const sp<AReplyToken> & replyToken)438 status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
439     if (replyToken == NULL) {
440         ALOGW("failed to post reply to a NULL token");
441         return -ENOENT;
442     }
443     sp<ALooper> looper = replyToken->getLooper();
444     if (looper == NULL) {
445         ALOGW("failed to post reply as target looper is gone.");
446         return -ENOENT;
447     }
448     return looper->postReply(replyToken, this);
449 }
450 
senderAwaitsResponse(sp<AReplyToken> * replyToken)451 bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
452     sp<RefBase> tmp;
453     bool found = findObject("replyID", &tmp);
454 
455     if (!found) {
456         return false;
457     }
458 
459     *replyToken = static_cast<AReplyToken *>(tmp.get());
460     tmp.clear();
461     setObject("replyID", tmp);
462     // TODO: delete Object instead of setting it to NULL
463 
464     return *replyToken != NULL;
465 }
466 
dup() const467 sp<AMessage> AMessage::dup() const {
468     sp<AMessage> msg = new AMessage(mWhat, mHandler.promote());
469     msg->mNumItems = mNumItems;
470 
471 #ifdef DUMP_STATS
472     {
473         Mutex::Autolock _l(gLock);
474         ++gDupCalls;
475         gAverageDupItems += mNumItems;
476         reportStats();
477     }
478 #endif
479 
480     for (size_t i = 0; i < mNumItems; ++i) {
481         const Item *from = &mItems[i];
482         Item *to = &msg->mItems[i];
483 
484         to->setName(from->mName, from->mNameLength);
485         to->mType = from->mType;
486 
487         switch (from->mType) {
488             case kTypeString:
489             {
490                 to->u.stringValue =
491                     new AString(*from->u.stringValue);
492                 break;
493             }
494 
495             case kTypeObject:
496             case kTypeBuffer:
497             {
498                 to->u.refValue = from->u.refValue;
499                 to->u.refValue->incStrong(msg.get());
500                 break;
501             }
502 
503             case kTypeMessage:
504             {
505                 sp<AMessage> copy =
506                     static_cast<AMessage *>(from->u.refValue)->dup();
507 
508                 to->u.refValue = copy.get();
509                 to->u.refValue->incStrong(msg.get());
510                 break;
511             }
512 
513             default:
514             {
515                 to->u = from->u;
516                 break;
517             }
518         }
519     }
520 
521     return msg;
522 }
523 
appendIndent(AString * s,int32_t indent)524 static void appendIndent(AString *s, int32_t indent) {
525     static const char kWhitespace[] =
526         "                                        "
527         "                                        ";
528 
529     CHECK_LT((size_t)indent, sizeof(kWhitespace));
530 
531     s->append(kWhitespace, indent);
532 }
533 
isFourcc(uint32_t what)534 static bool isFourcc(uint32_t what) {
535     return isprint(what & 0xff)
536         && isprint((what >> 8) & 0xff)
537         && isprint((what >> 16) & 0xff)
538         && isprint((what >> 24) & 0xff);
539 }
540 
debugString(int32_t indent) const541 AString AMessage::debugString(int32_t indent) const {
542     AString s = "AMessage(what = ";
543 
544     AString tmp;
545     if (isFourcc(mWhat)) {
546         tmp = AStringPrintf(
547                 "'%c%c%c%c'",
548                 (char)(mWhat >> 24),
549                 (char)((mWhat >> 16) & 0xff),
550                 (char)((mWhat >> 8) & 0xff),
551                 (char)(mWhat & 0xff));
552     } else {
553         tmp = AStringPrintf("0x%08x", mWhat);
554     }
555     s.append(tmp);
556 
557     if (mTarget != 0) {
558         tmp = AStringPrintf(", target = %d", mTarget);
559         s.append(tmp);
560     }
561     s.append(") = {\n");
562 
563     for (size_t i = 0; i < mNumItems; ++i) {
564         const Item &item = mItems[i];
565 
566         switch (item.mType) {
567             case kTypeInt32:
568                 tmp = AStringPrintf(
569                         "int32_t %s = %d", item.mName, item.u.int32Value);
570                 break;
571             case kTypeInt64:
572                 tmp = AStringPrintf(
573                         "int64_t %s = %lld", item.mName, item.u.int64Value);
574                 break;
575             case kTypeSize:
576                 tmp = AStringPrintf(
577                         "size_t %s = %d", item.mName, item.u.sizeValue);
578                 break;
579             case kTypeFloat:
580                 tmp = AStringPrintf(
581                         "float %s = %f", item.mName, item.u.floatValue);
582                 break;
583             case kTypeDouble:
584                 tmp = AStringPrintf(
585                         "double %s = %f", item.mName, item.u.doubleValue);
586                 break;
587             case kTypePointer:
588                 tmp = AStringPrintf(
589                         "void *%s = %p", item.mName, item.u.ptrValue);
590                 break;
591             case kTypeString:
592                 tmp = AStringPrintf(
593                         "string %s = \"%s\"",
594                         item.mName,
595                         item.u.stringValue->c_str());
596                 break;
597             case kTypeObject:
598                 tmp = AStringPrintf(
599                         "RefBase *%s = %p", item.mName, item.u.refValue);
600                 break;
601             case kTypeBuffer:
602             {
603                 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
604 
605                 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
606                     tmp = AStringPrintf("Buffer %s = {\n", item.mName);
607                     hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
608                     appendIndent(&tmp, indent + 2);
609                     tmp.append("}");
610                 } else {
611                     tmp = AStringPrintf(
612                             "Buffer *%s = %p", item.mName, buffer.get());
613                 }
614                 break;
615             }
616             case kTypeMessage:
617                 tmp = AStringPrintf(
618                         "AMessage %s = %s",
619                         item.mName,
620                         static_cast<AMessage *>(
621                             item.u.refValue)->debugString(
622                                 indent + strlen(item.mName) + 14).c_str());
623                 break;
624             case kTypeRect:
625                 tmp = AStringPrintf(
626                         "Rect %s(%d, %d, %d, %d)",
627                         item.mName,
628                         item.u.rectValue.mLeft,
629                         item.u.rectValue.mTop,
630                         item.u.rectValue.mRight,
631                         item.u.rectValue.mBottom);
632                 break;
633             default:
634                 TRESPASS();
635         }
636 
637         appendIndent(&s, indent);
638         s.append("  ");
639         s.append(tmp);
640         s.append("\n");
641     }
642 
643     appendIndent(&s, indent);
644     s.append("}");
645 
646     return s;
647 }
648 
649 #ifndef __ANDROID_VNDK__
650 // static
FromParcel(const Parcel & parcel,size_t maxNestingLevel)651 sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) {
652     int32_t what = parcel.readInt32();
653     sp<AMessage> msg = new AMessage();
654     msg->setWhat(what);
655 
656     msg->mNumItems = static_cast<size_t>(parcel.readInt32());
657     if (msg->mNumItems > kMaxNumItems) {
658         ALOGE("Too large number of items clipped.");
659         msg->mNumItems = kMaxNumItems;
660     }
661 
662     for (size_t i = 0; i < msg->mNumItems; ++i) {
663         Item *item = &msg->mItems[i];
664 
665         const char *name = parcel.readCString();
666         if (name == NULL) {
667             ALOGE("Failed reading name for an item. Parsing aborted.");
668             msg->mNumItems = i;
669             break;
670         }
671 
672         item->mType = static_cast<Type>(parcel.readInt32());
673         // setName() happens below so that we don't leak memory when parsing
674         // is aborted in the middle.
675         switch (item->mType) {
676             case kTypeInt32:
677             {
678                 item->u.int32Value = parcel.readInt32();
679                 break;
680             }
681 
682             case kTypeInt64:
683             {
684                 item->u.int64Value = parcel.readInt64();
685                 break;
686             }
687 
688             case kTypeSize:
689             {
690                 item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
691                 break;
692             }
693 
694             case kTypeFloat:
695             {
696                 item->u.floatValue = parcel.readFloat();
697                 break;
698             }
699 
700             case kTypeDouble:
701             {
702                 item->u.doubleValue = parcel.readDouble();
703                 break;
704             }
705 
706             case kTypeString:
707             {
708                 const char *stringValue = parcel.readCString();
709                 if (stringValue == NULL) {
710                     ALOGE("Failed reading string value from a parcel. "
711                         "Parsing aborted.");
712                     msg->mNumItems = i;
713                     continue;
714                     // The loop will terminate subsequently.
715                 } else {
716                     item->u.stringValue = new AString(stringValue);
717                 }
718                 break;
719             }
720 
721             case kTypeMessage:
722             {
723                 if (maxNestingLevel == 0) {
724                     ALOGE("Too many levels of AMessage nesting.");
725                     return NULL;
726                 }
727                 sp<AMessage> subMsg = AMessage::FromParcel(
728                         parcel,
729                         maxNestingLevel - 1);
730                 if (subMsg == NULL) {
731                     // This condition will be triggered when there exists an
732                     // object that cannot cross process boundaries or when the
733                     // level of nested AMessage is too deep.
734                     return NULL;
735                 }
736                 subMsg->incStrong(msg.get());
737 
738                 item->u.refValue = subMsg.get();
739                 break;
740             }
741 
742             default:
743             {
744                 ALOGE("This type of object cannot cross process boundaries.");
745                 return NULL;
746             }
747         }
748 
749         item->setName(name, strlen(name));
750     }
751 
752     return msg;
753 }
754 
writeToParcel(Parcel * parcel) const755 void AMessage::writeToParcel(Parcel *parcel) const {
756     parcel->writeInt32(static_cast<int32_t>(mWhat));
757     parcel->writeInt32(static_cast<int32_t>(mNumItems));
758 
759     for (size_t i = 0; i < mNumItems; ++i) {
760         const Item &item = mItems[i];
761 
762         parcel->writeCString(item.mName);
763         parcel->writeInt32(static_cast<int32_t>(item.mType));
764 
765         switch (item.mType) {
766             case kTypeInt32:
767             {
768                 parcel->writeInt32(item.u.int32Value);
769                 break;
770             }
771 
772             case kTypeInt64:
773             {
774                 parcel->writeInt64(item.u.int64Value);
775                 break;
776             }
777 
778             case kTypeSize:
779             {
780                 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
781                 break;
782             }
783 
784             case kTypeFloat:
785             {
786                 parcel->writeFloat(item.u.floatValue);
787                 break;
788             }
789 
790             case kTypeDouble:
791             {
792                 parcel->writeDouble(item.u.doubleValue);
793                 break;
794             }
795 
796             case kTypeString:
797             {
798                 parcel->writeCString(item.u.stringValue->c_str());
799                 break;
800             }
801 
802             case kTypeMessage:
803             {
804                 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
805                 break;
806             }
807 
808             default:
809             {
810                 ALOGE("This type of object cannot cross process boundaries.");
811                 TRESPASS();
812             }
813         }
814     }
815 }
816 #endif  // __ANDROID_VNDK__
817 
changesFrom(const sp<const AMessage> & other,bool deep) const818 sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const {
819     if (other == NULL) {
820         return const_cast<AMessage*>(this);
821     }
822 
823     sp<AMessage> diff = new AMessage;
824     if (mWhat != other->mWhat) {
825         diff->setWhat(mWhat);
826     }
827     if (mHandler != other->mHandler) {
828         diff->setTarget(mHandler.promote());
829     }
830 
831     for (size_t i = 0; i < mNumItems; ++i) {
832         const Item &item = mItems[i];
833         const Item *oitem = other->findItem(item.mName, item.mType);
834         switch (item.mType) {
835             case kTypeInt32:
836                 if (oitem == NULL || item.u.int32Value != oitem->u.int32Value) {
837                     diff->setInt32(item.mName, item.u.int32Value);
838                 }
839                 break;
840 
841             case kTypeInt64:
842                 if (oitem == NULL || item.u.int64Value != oitem->u.int64Value) {
843                     diff->setInt64(item.mName, item.u.int64Value);
844                 }
845                 break;
846 
847             case kTypeSize:
848                 if (oitem == NULL || item.u.sizeValue != oitem->u.sizeValue) {
849                     diff->setSize(item.mName, item.u.sizeValue);
850                 }
851                 break;
852 
853             case kTypeFloat:
854                 if (oitem == NULL || item.u.floatValue != oitem->u.floatValue) {
855                     diff->setFloat(item.mName, item.u.sizeValue);
856                 }
857                 break;
858 
859             case kTypeDouble:
860                 if (oitem == NULL || item.u.doubleValue != oitem->u.doubleValue) {
861                     diff->setDouble(item.mName, item.u.sizeValue);
862                 }
863                 break;
864 
865             case kTypeString:
866                 if (oitem == NULL || *item.u.stringValue != *oitem->u.stringValue) {
867                     diff->setString(item.mName, *item.u.stringValue);
868                 }
869                 break;
870 
871             case kTypeRect:
872                 if (oitem == NULL || memcmp(&item.u.rectValue, &oitem->u.rectValue, sizeof(Rect))) {
873                     diff->setRect(
874                             item.mName, item.u.rectValue.mLeft, item.u.rectValue.mTop,
875                             item.u.rectValue.mRight, item.u.rectValue.mBottom);
876                 }
877                 break;
878 
879             case kTypePointer:
880                 if (oitem == NULL || item.u.ptrValue != oitem->u.ptrValue) {
881                     diff->setPointer(item.mName, item.u.ptrValue);
882                 }
883                 break;
884 
885             case kTypeBuffer:
886             {
887                 sp<ABuffer> myBuf = static_cast<ABuffer *>(item.u.refValue);
888                 if (myBuf == NULL) {
889                     if (oitem == NULL || oitem->u.refValue != NULL) {
890                         diff->setBuffer(item.mName, NULL);
891                     }
892                     break;
893                 }
894                 sp<ABuffer> oBuf = oitem == NULL ? NULL : static_cast<ABuffer *>(oitem->u.refValue);
895                 if (oBuf == NULL
896                         || myBuf->size() != oBuf->size()
897                         || (!myBuf->data() ^ !oBuf->data()) // data nullness differs
898                         || (myBuf->data() && memcmp(myBuf->data(), oBuf->data(), myBuf->size()))) {
899                     diff->setBuffer(item.mName, myBuf);
900                 }
901                 break;
902             }
903 
904             case kTypeMessage:
905             {
906                 sp<AMessage> myMsg = static_cast<AMessage *>(item.u.refValue);
907                 if (myMsg == NULL) {
908                     if (oitem == NULL || oitem->u.refValue != NULL) {
909                         diff->setMessage(item.mName, NULL);
910                     }
911                     break;
912                 }
913                 sp<AMessage> oMsg =
914                     oitem == NULL ? NULL : static_cast<AMessage *>(oitem->u.refValue);
915                 sp<AMessage> changes = myMsg->changesFrom(oMsg, deep);
916                 if (changes->countEntries()) {
917                     diff->setMessage(item.mName, deep ? changes : myMsg);
918                 }
919                 break;
920             }
921 
922             case kTypeObject:
923                 if (oitem == NULL || item.u.refValue != oitem->u.refValue) {
924                     diff->setObject(item.mName, item.u.refValue);
925                 }
926                 break;
927 
928             default:
929             {
930                 ALOGE("Unknown type %d", item.mType);
931                 TRESPASS();
932             }
933         }
934     }
935     return diff;
936 }
937 
countEntries() const938 size_t AMessage::countEntries() const {
939     return mNumItems;
940 }
941 
getEntryNameAt(size_t index,Type * type) const942 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
943     if (index >= mNumItems) {
944         *type = kTypeInt32;
945 
946         return NULL;
947     }
948 
949     *type = mItems[index].mType;
950 
951     return mItems[index].mName;
952 }
953 
getEntryAt(size_t index) const954 AMessage::ItemData AMessage::getEntryAt(size_t index) const {
955     ItemData it;
956     if (index < mNumItems) {
957         switch (mItems[index].mType) {
958             case kTypeInt32:    it.set(mItems[index].u.int32Value); break;
959             case kTypeInt64:    it.set(mItems[index].u.int64Value); break;
960             case kTypeSize:     it.set(mItems[index].u.sizeValue); break;
961             case kTypeFloat:    it.set(mItems[index].u.floatValue); break;
962             case kTypeDouble:   it.set(mItems[index].u.doubleValue); break;
963             case kTypePointer:  it.set(mItems[index].u.ptrValue); break;
964             case kTypeRect:     it.set(mItems[index].u.rectValue); break;
965             case kTypeString:   it.set(*mItems[index].u.stringValue); break;
966             case kTypeObject: {
967                 sp<RefBase> obj = mItems[index].u.refValue;
968                 it.set(obj);
969                 break;
970             }
971             case kTypeMessage: {
972                 sp<AMessage> msg = static_cast<AMessage *>(mItems[index].u.refValue);
973                 it.set(msg);
974                 break;
975             }
976             case kTypeBuffer: {
977                 sp<ABuffer> buf = static_cast<ABuffer *>(mItems[index].u.refValue);
978                 it.set(buf);
979                 break;
980             }
981             default:
982                 break;
983         }
984     }
985     return it;
986 }
987 
setEntryNameAt(size_t index,const char * name)988 status_t AMessage::setEntryNameAt(size_t index, const char *name) {
989     if (index >= mNumItems) {
990         return BAD_INDEX;
991     }
992     if (name == nullptr) {
993         return BAD_VALUE;
994     }
995     if (!strcmp(name, mItems[index].mName)) {
996         return OK; // name has not changed
997     }
998     size_t len = strlen(name);
999     if (findItemIndex(name, len) < mNumItems) {
1000         return ALREADY_EXISTS;
1001     }
1002     delete[] mItems[index].mName;
1003     mItems[index].mName = nullptr;
1004     mItems[index].setName(name, len);
1005     return OK;
1006 }
1007 
setEntryAt(size_t index,const ItemData & item)1008 status_t AMessage::setEntryAt(size_t index, const ItemData &item) {
1009     AString stringValue;
1010     sp<RefBase> refValue;
1011     sp<AMessage> msgValue;
1012     sp<ABuffer> bufValue;
1013 
1014     if (index >= mNumItems) {
1015         return BAD_INDEX;
1016     }
1017     if (!item.used()) {
1018         return BAD_VALUE;
1019     }
1020     Item *dst = &mItems[index];
1021     freeItemValue(dst);
1022 
1023     // some values can be directly set with the getter. others need items to be allocated
1024     if (item.find(&dst->u.int32Value)) {
1025         dst->mType = kTypeInt32;
1026     } else if (item.find(&dst->u.int64Value)) {
1027         dst->mType = kTypeInt64;
1028     } else if (item.find(&dst->u.sizeValue)) {
1029         dst->mType = kTypeSize;
1030     } else if (item.find(&dst->u.floatValue)) {
1031         dst->mType = kTypeFloat;
1032     } else if (item.find(&dst->u.doubleValue)) {
1033         dst->mType = kTypeDouble;
1034     } else if (item.find(&dst->u.ptrValue)) {
1035         dst->mType = kTypePointer;
1036     } else if (item.find(&dst->u.rectValue)) {
1037         dst->mType = kTypeRect;
1038     } else if (item.find(&stringValue)) {
1039         dst->u.stringValue = new AString(stringValue);
1040         dst->mType = kTypeString;
1041     } else if (item.find(&refValue)) {
1042         if (refValue != NULL) { refValue->incStrong(this); }
1043         dst->u.refValue = refValue.get();
1044         dst->mType = kTypeObject;
1045     } else if (item.find(&msgValue)) {
1046         if (msgValue != NULL) { msgValue->incStrong(this); }
1047         dst->u.refValue = msgValue.get();
1048         dst->mType = kTypeMessage;
1049     } else if (item.find(&bufValue)) {
1050         if (bufValue != NULL) { bufValue->incStrong(this); }
1051         dst->u.refValue = bufValue.get();
1052         dst->mType = kTypeBuffer;
1053     } else {
1054         // unsupported item - we should not be here.
1055         dst->mType = kTypeInt32;
1056         dst->u.int32Value = 0xDEADDEAD;
1057         return BAD_TYPE;
1058     }
1059     return OK;
1060 }
1061 
removeEntryAt(size_t index)1062 status_t AMessage::removeEntryAt(size_t index) {
1063     if (index >= mNumItems) {
1064         return BAD_INDEX;
1065     }
1066     // delete entry data and objects
1067     --mNumItems;
1068     delete[] mItems[index].mName;
1069     mItems[index].mName = nullptr;
1070     freeItemValue(&mItems[index]);
1071 
1072     // swap entry with last entry and clear last entry's data
1073     if (index < mNumItems) {
1074         mItems[index] = mItems[mNumItems];
1075         mItems[mNumItems].mName = nullptr;
1076         mItems[mNumItems].mType = kTypeInt32;
1077     }
1078     return OK;
1079 }
1080 
setItem(const char * name,const ItemData & item)1081 void AMessage::setItem(const char *name, const ItemData &item) {
1082     if (item.used()) {
1083         Item *it = allocateItem(name);
1084         if (it != nullptr) {
1085             setEntryAt(it - mItems, item);
1086         }
1087     }
1088 }
1089 
findItem(const char * name) const1090 AMessage::ItemData AMessage::findItem(const char *name) const {
1091     return getEntryAt(findEntryByName(name));
1092 }
1093 
extend(const sp<AMessage> & other)1094 void AMessage::extend(const sp<AMessage> &other) {
1095     // ignore null messages
1096     if (other == nullptr) {
1097         return;
1098     }
1099 
1100     for (size_t ix = 0; ix < other->mNumItems; ++ix) {
1101         Item *it = allocateItem(other->mItems[ix].mName);
1102         if (it != nullptr) {
1103             ItemData data = other->getEntryAt(ix);
1104             setEntryAt(it - mItems, data);
1105         }
1106     }
1107 }
1108 
findEntryByName(const char * name) const1109 size_t AMessage::findEntryByName(const char *name) const {
1110     return name == nullptr ? countEntries() : findItemIndex(name, strlen(name));
1111 }
1112 
1113 }  // namespace android
1114