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