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