1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "AMessage"
18 //#define LOG_NDEBUG 0
19 //#define DUMP_STATS
20 #include <cutils/log.h>
21
22 #include "AMessage.h"
23
24 #include <ctype.h>
25
26 #include "AAtomizer.h"
27 #include "ABuffer.h"
28 #include "ADebug.h"
29 #include "ALooperRoster.h"
30 #include "AHandler.h"
31 #include "AString.h"
32
33 #include <binder/Parcel.h>
34 #include <media/stagefright/foundation/hexdump.h>
35
36 namespace android {
37
38 extern ALooperRoster gLooperRoster;
39
setReply(const sp<AMessage> & reply)40 status_t AReplyToken::setReply(const sp<AMessage> &reply) {
41 if (mReplied) {
42 ALOGE("trying to post a duplicate reply");
43 return -EBUSY;
44 }
45 CHECK(mReply == NULL);
46 mReply = reply;
47 mReplied = true;
48 return OK;
49 }
50
AMessage(void)51 AMessage::AMessage(void)
52 : mWhat(0),
53 mTarget(0),
54 mNumItems(0) {
55 }
56
AMessage(uint32_t what,const sp<const AHandler> & handler)57 AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
58 : mWhat(what),
59 mNumItems(0) {
60 setTarget(handler);
61 }
62
~AMessage()63 AMessage::~AMessage() {
64 clear();
65 }
66
setWhat(uint32_t what)67 void AMessage::setWhat(uint32_t what) {
68 mWhat = what;
69 }
70
what() const71 uint32_t AMessage::what() const {
72 return mWhat;
73 }
74
setTarget(const sp<const AHandler> & handler)75 void AMessage::setTarget(const sp<const AHandler> &handler) {
76 if (handler == NULL) {
77 mTarget = 0;
78 mHandler.clear();
79 mLooper.clear();
80 } else {
81 mTarget = handler->id();
82 mHandler = handler->getHandler();
83 mLooper = handler->getLooper();
84 }
85 }
86
clear()87 void AMessage::clear() {
88 for (size_t i = 0; i < mNumItems; ++i) {
89 Item *item = &mItems[i];
90 delete[] item->mName;
91 item->mName = NULL;
92 freeItemValue(item);
93 }
94 mNumItems = 0;
95 }
96
freeItemValue(Item * item)97 void AMessage::freeItemValue(Item *item) {
98 switch (item->mType) {
99 case kTypeString:
100 {
101 delete item->u.stringValue;
102 break;
103 }
104
105 case kTypeObject:
106 case kTypeMessage:
107 case kTypeBuffer:
108 {
109 if (item->u.refValue != NULL) {
110 item->u.refValue->decStrong(this);
111 }
112 break;
113 }
114
115 default:
116 break;
117 }
118 }
119
120 #ifdef DUMP_STATS
121 #include <utils/Mutex.h>
122
123 Mutex gLock;
124 static int32_t gFindItemCalls = 1;
125 static int32_t gDupCalls = 1;
126 static int32_t gAverageNumItems = 0;
127 static int32_t gAverageNumChecks = 0;
128 static int32_t gAverageNumMemChecks = 0;
129 static int32_t gAverageDupItems = 0;
130 static int32_t gLastChecked = -1;
131
reportStats()132 static void reportStats() {
133 int32_t time = (ALooper::GetNowUs() / 1000);
134 if (time / 1000 != gLastChecked / 1000) {
135 gLastChecked = time;
136 ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)",
137 gFindItemCalls,
138 gAverageNumItems / (float)gFindItemCalls,
139 gAverageNumChecks / (float)gFindItemCalls,
140 gAverageNumMemChecks / (float)gFindItemCalls,
141 gDupCalls,
142 gAverageDupItems / (float)gDupCalls);
143 gFindItemCalls = gDupCalls = 1;
144 gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0;
145 gLastChecked = time;
146 }
147 }
148 #endif
149
findItemIndex(const char * name,size_t len) const150 inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
151 #ifdef DUMP_STATS
152 size_t memchecks = 0;
153 #endif
154 size_t i = 0;
155 for (; i < mNumItems; i++) {
156 if (len != mItems[i].mNameLength) {
157 continue;
158 }
159 #ifdef DUMP_STATS
160 ++memchecks;
161 #endif
162 if (!memcmp(mItems[i].mName, name, len)) {
163 break;
164 }
165 }
166 #ifdef DUMP_STATS
167 {
168 Mutex::Autolock _l(gLock);
169 ++gFindItemCalls;
170 gAverageNumItems += mNumItems;
171 gAverageNumMemChecks += memchecks;
172 gAverageNumChecks += i;
173 reportStats();
174 }
175 #endif
176 return i;
177 }
178
179 // assumes item's name was uninitialized or NULL
setName(const char * name,size_t len)180 void AMessage::Item::setName(const char *name, size_t len) {
181 mNameLength = len;
182 mName = new char[len + 1];
183 memcpy((void*)mName, name, len + 1);
184 }
185
allocateItem(const char * name)186 AMessage::Item *AMessage::allocateItem(const char *name) {
187 size_t len = strlen(name);
188 size_t i = findItemIndex(name, len);
189 Item *item;
190
191 if (i < mNumItems) {
192 item = &mItems[i];
193 freeItemValue(item);
194 } else {
195 CHECK(mNumItems < kMaxNumItems);
196 i = mNumItems++;
197 item = &mItems[i];
198 item->setName(name, len);
199 }
200
201 return item;
202 }
203
findItem(const char * name,Type type) const204 const AMessage::Item *AMessage::findItem(
205 const char *name, Type type) const {
206 size_t i = findItemIndex(name, strlen(name));
207 if (i < mNumItems) {
208 const Item *item = &mItems[i];
209 return item->mType == type ? item : NULL;
210
211 }
212 return NULL;
213 }
214
findAsFloat(const char * name,float * value) const215 bool AMessage::findAsFloat(const char *name, float *value) const {
216 size_t i = findItemIndex(name, strlen(name));
217 if (i < mNumItems) {
218 const Item *item = &mItems[i];
219 switch (item->mType) {
220 case kTypeFloat:
221 *value = item->u.floatValue;
222 return true;
223 case kTypeDouble:
224 *value = (float)item->u.doubleValue;
225 return true;
226 case kTypeInt64:
227 *value = (float)item->u.int64Value;
228 return true;
229 case kTypeInt32:
230 *value = (float)item->u.int32Value;
231 return true;
232 case kTypeSize:
233 *value = (float)item->u.sizeValue;
234 return true;
235 default:
236 return false;
237 }
238 }
239 return false;
240 }
241
contains(const char * name) const242 bool AMessage::contains(const char *name) const {
243 size_t i = findItemIndex(name, strlen(name));
244 return i < mNumItems;
245 }
246
247 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \
248 void AMessage::set##NAME(const char *name, TYPENAME value) { \
249 Item *item = allocateItem(name); \
250 \
251 item->mType = kType##NAME; \
252 item->u.FIELDNAME = value; \
253 } \
254 \
255 bool AMessage::find##NAME(const char *name, TYPENAME *value) const { \
256 const Item *item = findItem(name, kType##NAME); \
257 if (item) { \
258 *value = item->u.FIELDNAME; \
259 return true; \
260 } \
261 return false; \
262 }
263
BASIC_TYPE(Int32,int32Value,int32_t)264 BASIC_TYPE(Int32,int32Value,int32_t)
265 BASIC_TYPE(Int64,int64Value,int64_t)
266 BASIC_TYPE(Size,sizeValue,size_t)
267 BASIC_TYPE(Float,floatValue,float)
268 BASIC_TYPE(Double,doubleValue,double)
269 BASIC_TYPE(Pointer,ptrValue,void *)
270
271 #undef BASIC_TYPE
272
273 void AMessage::setString(
274 const char *name, const char *s, ssize_t len) {
275 Item *item = allocateItem(name);
276 item->mType = kTypeString;
277 item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
278 }
279
setString(const char * name,const AString & s)280 void AMessage::setString(
281 const char *name, const AString &s) {
282 setString(name, s.c_str(), s.size());
283 }
284
setObjectInternal(const char * name,const sp<RefBase> & obj,Type type)285 void AMessage::setObjectInternal(
286 const char *name, const sp<RefBase> &obj, Type type) {
287 Item *item = allocateItem(name);
288 item->mType = type;
289
290 if (obj != NULL) { obj->incStrong(this); }
291 item->u.refValue = obj.get();
292 }
293
setObject(const char * name,const sp<RefBase> & obj)294 void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
295 setObjectInternal(name, obj, kTypeObject);
296 }
297
setBuffer(const char * name,const sp<ABuffer> & buffer)298 void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
299 setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
300 }
301
setMessage(const char * name,const sp<AMessage> & obj)302 void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
303 Item *item = allocateItem(name);
304 item->mType = kTypeMessage;
305
306 if (obj != NULL) { obj->incStrong(this); }
307 item->u.refValue = obj.get();
308 }
309
setRect(const char * name,int32_t left,int32_t top,int32_t right,int32_t bottom)310 void AMessage::setRect(
311 const char *name,
312 int32_t left, int32_t top, int32_t right, int32_t bottom) {
313 Item *item = allocateItem(name);
314 item->mType = kTypeRect;
315
316 item->u.rectValue.mLeft = left;
317 item->u.rectValue.mTop = top;
318 item->u.rectValue.mRight = right;
319 item->u.rectValue.mBottom = bottom;
320 }
321
findString(const char * name,AString * value) const322 bool AMessage::findString(const char *name, AString *value) const {
323 const Item *item = findItem(name, kTypeString);
324 if (item) {
325 *value = *item->u.stringValue;
326 return true;
327 }
328 return false;
329 }
330
findObject(const char * name,sp<RefBase> * obj) const331 bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
332 const Item *item = findItem(name, kTypeObject);
333 if (item) {
334 *obj = item->u.refValue;
335 return true;
336 }
337 return false;
338 }
339
findBuffer(const char * name,sp<ABuffer> * buf) const340 bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const {
341 const Item *item = findItem(name, kTypeBuffer);
342 if (item) {
343 *buf = (ABuffer *)(item->u.refValue);
344 return true;
345 }
346 return false;
347 }
348
findMessage(const char * name,sp<AMessage> * obj) const349 bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
350 const Item *item = findItem(name, kTypeMessage);
351 if (item) {
352 *obj = static_cast<AMessage *>(item->u.refValue);
353 return true;
354 }
355 return false;
356 }
357
findRect(const char * name,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const358 bool AMessage::findRect(
359 const char *name,
360 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
361 const Item *item = findItem(name, kTypeRect);
362 if (item == NULL) {
363 return false;
364 }
365
366 *left = item->u.rectValue.mLeft;
367 *top = item->u.rectValue.mTop;
368 *right = item->u.rectValue.mRight;
369 *bottom = item->u.rectValue.mBottom;
370
371 return true;
372 }
373
deliver()374 void AMessage::deliver() {
375 sp<AHandler> handler = mHandler.promote();
376 if (handler == NULL) {
377 ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
378 return;
379 }
380
381 handler->deliverMessage(this);
382 }
383
post(int64_t delayUs)384 status_t AMessage::post(int64_t delayUs) {
385 sp<ALooper> looper = mLooper.promote();
386 if (looper == NULL) {
387 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
388 return -ENOENT;
389 }
390
391 looper->post(this, delayUs);
392 return OK;
393 }
394
postAndAwaitResponse(sp<AMessage> * response)395 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
396 sp<ALooper> looper = mLooper.promote();
397 if (looper == NULL) {
398 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
399 return -ENOENT;
400 }
401
402 sp<AReplyToken> token = looper->createReplyToken();
403 if (token == NULL) {
404 ALOGE("failed to create reply token");
405 return -ENOMEM;
406 }
407 setObject("replyID", token);
408
409 looper->post(this, 0 /* delayUs */);
410 return looper->awaitResponse(token, response);
411 }
412
postReply(const sp<AReplyToken> & replyToken)413 status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
414 if (replyToken == NULL) {
415 ALOGW("failed to post reply to a NULL token");
416 return -ENOENT;
417 }
418 sp<ALooper> looper = replyToken->getLooper();
419 if (looper == NULL) {
420 ALOGW("failed to post reply as target looper is gone.");
421 return -ENOENT;
422 }
423 return looper->postReply(replyToken, this);
424 }
425
senderAwaitsResponse(sp<AReplyToken> * replyToken)426 bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
427 sp<RefBase> tmp;
428 bool found = findObject("replyID", &tmp);
429
430 if (!found) {
431 return false;
432 }
433
434 *replyToken = static_cast<AReplyToken *>(tmp.get());
435 tmp.clear();
436 setObject("replyID", tmp);
437 // TODO: delete Object instead of setting it to NULL
438
439 return *replyToken != NULL;
440 }
441
dup() const442 sp<AMessage> AMessage::dup() const {
443 sp<AMessage> msg = new AMessage(mWhat, mHandler.promote());
444 msg->mNumItems = mNumItems;
445
446 #ifdef DUMP_STATS
447 {
448 Mutex::Autolock _l(gLock);
449 ++gDupCalls;
450 gAverageDupItems += mNumItems;
451 reportStats();
452 }
453 #endif
454
455 for (size_t i = 0; i < mNumItems; ++i) {
456 const Item *from = &mItems[i];
457 Item *to = &msg->mItems[i];
458
459 to->setName(from->mName, from->mNameLength);
460 to->mType = from->mType;
461
462 switch (from->mType) {
463 case kTypeString:
464 {
465 to->u.stringValue =
466 new AString(*from->u.stringValue);
467 break;
468 }
469
470 case kTypeObject:
471 case kTypeBuffer:
472 {
473 to->u.refValue = from->u.refValue;
474 to->u.refValue->incStrong(msg.get());
475 break;
476 }
477
478 case kTypeMessage:
479 {
480 sp<AMessage> copy =
481 static_cast<AMessage *>(from->u.refValue)->dup();
482
483 to->u.refValue = copy.get();
484 to->u.refValue->incStrong(msg.get());
485 break;
486 }
487
488 default:
489 {
490 to->u = from->u;
491 break;
492 }
493 }
494 }
495
496 return msg;
497 }
498
appendIndent(AString * s,int32_t indent)499 static void appendIndent(AString *s, int32_t indent) {
500 static const char kWhitespace[] =
501 " "
502 " ";
503
504 CHECK_LT((size_t)indent, sizeof(kWhitespace));
505
506 s->append(kWhitespace, indent);
507 }
508
isFourcc(uint32_t what)509 static bool isFourcc(uint32_t what) {
510 return isprint(what & 0xff)
511 && isprint((what >> 8) & 0xff)
512 && isprint((what >> 16) & 0xff)
513 && isprint((what >> 24) & 0xff);
514 }
515
debugString(int32_t indent) const516 AString AMessage::debugString(int32_t indent) const {
517 AString s = "AMessage(what = ";
518
519 AString tmp;
520 if (isFourcc(mWhat)) {
521 tmp = AStringPrintf(
522 "'%c%c%c%c'",
523 (char)(mWhat >> 24),
524 (char)((mWhat >> 16) & 0xff),
525 (char)((mWhat >> 8) & 0xff),
526 (char)(mWhat & 0xff));
527 } else {
528 tmp = AStringPrintf("0x%08x", mWhat);
529 }
530 s.append(tmp);
531
532 if (mTarget != 0) {
533 tmp = AStringPrintf(", target = %d", mTarget);
534 s.append(tmp);
535 }
536 s.append(") = {\n");
537
538 for (size_t i = 0; i < mNumItems; ++i) {
539 const Item &item = mItems[i];
540
541 switch (item.mType) {
542 case kTypeInt32:
543 tmp = AStringPrintf(
544 "int32_t %s = %d", item.mName, item.u.int32Value);
545 break;
546 case kTypeInt64:
547 tmp = AStringPrintf(
548 "int64_t %s = %lld", item.mName, item.u.int64Value);
549 break;
550 case kTypeSize:
551 tmp = AStringPrintf(
552 "size_t %s = %d", item.mName, item.u.sizeValue);
553 break;
554 case kTypeFloat:
555 tmp = AStringPrintf(
556 "float %s = %f", item.mName, item.u.floatValue);
557 break;
558 case kTypeDouble:
559 tmp = AStringPrintf(
560 "double %s = %f", item.mName, item.u.doubleValue);
561 break;
562 case kTypePointer:
563 tmp = AStringPrintf(
564 "void *%s = %p", item.mName, item.u.ptrValue);
565 break;
566 case kTypeString:
567 tmp = AStringPrintf(
568 "string %s = \"%s\"",
569 item.mName,
570 item.u.stringValue->c_str());
571 break;
572 case kTypeObject:
573 tmp = AStringPrintf(
574 "RefBase *%s = %p", item.mName, item.u.refValue);
575 break;
576 case kTypeBuffer:
577 {
578 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
579
580 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
581 tmp = AStringPrintf("Buffer %s = {\n", item.mName);
582 hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
583 appendIndent(&tmp, indent + 2);
584 tmp.append("}");
585 } else {
586 tmp = AStringPrintf(
587 "Buffer *%s = %p", item.mName, buffer.get());
588 }
589 break;
590 }
591 case kTypeMessage:
592 tmp = AStringPrintf(
593 "AMessage %s = %s",
594 item.mName,
595 static_cast<AMessage *>(
596 item.u.refValue)->debugString(
597 indent + strlen(item.mName) + 14).c_str());
598 break;
599 case kTypeRect:
600 tmp = AStringPrintf(
601 "Rect %s(%d, %d, %d, %d)",
602 item.mName,
603 item.u.rectValue.mLeft,
604 item.u.rectValue.mTop,
605 item.u.rectValue.mRight,
606 item.u.rectValue.mBottom);
607 break;
608 default:
609 TRESPASS();
610 }
611
612 appendIndent(&s, indent);
613 s.append(" ");
614 s.append(tmp);
615 s.append("\n");
616 }
617
618 appendIndent(&s, indent);
619 s.append("}");
620
621 return s;
622 }
623
624 // static
FromParcel(const Parcel & parcel,size_t maxNestingLevel)625 sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) {
626 int32_t what = parcel.readInt32();
627 sp<AMessage> msg = new AMessage();
628 msg->setWhat(what);
629
630 msg->mNumItems = static_cast<size_t>(parcel.readInt32());
631 if (msg->mNumItems > kMaxNumItems) {
632 ALOGE("Too large number of items clipped.");
633 msg->mNumItems = kMaxNumItems;
634 }
635
636 for (size_t i = 0; i < msg->mNumItems; ++i) {
637 Item *item = &msg->mItems[i];
638
639 const char *name = parcel.readCString();
640 if (name == NULL) {
641 ALOGE("Failed reading name for an item. Parsing aborted.");
642 msg->mNumItems = i;
643 break;
644 }
645
646 item->mType = static_cast<Type>(parcel.readInt32());
647 // setName() happens below so that we don't leak memory when parsing
648 // is aborted in the middle.
649 switch (item->mType) {
650 case kTypeInt32:
651 {
652 item->u.int32Value = parcel.readInt32();
653 break;
654 }
655
656 case kTypeInt64:
657 {
658 item->u.int64Value = parcel.readInt64();
659 break;
660 }
661
662 case kTypeSize:
663 {
664 item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
665 break;
666 }
667
668 case kTypeFloat:
669 {
670 item->u.floatValue = parcel.readFloat();
671 break;
672 }
673
674 case kTypeDouble:
675 {
676 item->u.doubleValue = parcel.readDouble();
677 break;
678 }
679
680 case kTypeString:
681 {
682 const char *stringValue = parcel.readCString();
683 if (stringValue == NULL) {
684 ALOGE("Failed reading string value from a parcel. "
685 "Parsing aborted.");
686 msg->mNumItems = i;
687 continue;
688 // The loop will terminate subsequently.
689 } else {
690 item->u.stringValue = new AString(stringValue);
691 }
692 break;
693 }
694
695 case kTypeMessage:
696 {
697 if (maxNestingLevel == 0) {
698 ALOGE("Too many levels of AMessage nesting.");
699 return NULL;
700 }
701 sp<AMessage> subMsg = AMessage::FromParcel(
702 parcel,
703 maxNestingLevel - 1);
704 if (subMsg == NULL) {
705 // This condition will be triggered when there exists an
706 // object that cannot cross process boundaries or when the
707 // level of nested AMessage is too deep.
708 return NULL;
709 }
710 subMsg->incStrong(msg.get());
711
712 item->u.refValue = subMsg.get();
713 break;
714 }
715
716 default:
717 {
718 ALOGE("This type of object cannot cross process boundaries.");
719 return NULL;
720 }
721 }
722
723 item->setName(name, strlen(name));
724 }
725
726 return msg;
727 }
728
writeToParcel(Parcel * parcel) const729 void AMessage::writeToParcel(Parcel *parcel) const {
730 parcel->writeInt32(static_cast<int32_t>(mWhat));
731 parcel->writeInt32(static_cast<int32_t>(mNumItems));
732
733 for (size_t i = 0; i < mNumItems; ++i) {
734 const Item &item = mItems[i];
735
736 parcel->writeCString(item.mName);
737 parcel->writeInt32(static_cast<int32_t>(item.mType));
738
739 switch (item.mType) {
740 case kTypeInt32:
741 {
742 parcel->writeInt32(item.u.int32Value);
743 break;
744 }
745
746 case kTypeInt64:
747 {
748 parcel->writeInt64(item.u.int64Value);
749 break;
750 }
751
752 case kTypeSize:
753 {
754 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
755 break;
756 }
757
758 case kTypeFloat:
759 {
760 parcel->writeFloat(item.u.floatValue);
761 break;
762 }
763
764 case kTypeDouble:
765 {
766 parcel->writeDouble(item.u.doubleValue);
767 break;
768 }
769
770 case kTypeString:
771 {
772 parcel->writeCString(item.u.stringValue->c_str());
773 break;
774 }
775
776 case kTypeMessage:
777 {
778 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
779 break;
780 }
781
782 default:
783 {
784 ALOGE("This type of object cannot cross process boundaries.");
785 TRESPASS();
786 }
787 }
788 }
789 }
790
changesFrom(const sp<const AMessage> & other,bool deep) const791 sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const {
792 if (other == NULL) {
793 return const_cast<AMessage*>(this);
794 }
795
796 sp<AMessage> diff = new AMessage;
797 if (mWhat != other->mWhat) {
798 diff->setWhat(mWhat);
799 }
800 if (mHandler != other->mHandler) {
801 diff->setTarget(mHandler.promote());
802 }
803
804 for (size_t i = 0; i < mNumItems; ++i) {
805 const Item &item = mItems[i];
806 const Item *oitem = other->findItem(item.mName, item.mType);
807 switch (item.mType) {
808 case kTypeInt32:
809 if (oitem == NULL || item.u.int32Value != oitem->u.int32Value) {
810 diff->setInt32(item.mName, item.u.int32Value);
811 }
812 break;
813
814 case kTypeInt64:
815 if (oitem == NULL || item.u.int64Value != oitem->u.int64Value) {
816 diff->setInt64(item.mName, item.u.int64Value);
817 }
818 break;
819
820 case kTypeSize:
821 if (oitem == NULL || item.u.sizeValue != oitem->u.sizeValue) {
822 diff->setSize(item.mName, item.u.sizeValue);
823 }
824 break;
825
826 case kTypeFloat:
827 if (oitem == NULL || item.u.floatValue != oitem->u.floatValue) {
828 diff->setFloat(item.mName, item.u.sizeValue);
829 }
830 break;
831
832 case kTypeDouble:
833 if (oitem == NULL || item.u.doubleValue != oitem->u.doubleValue) {
834 diff->setDouble(item.mName, item.u.sizeValue);
835 }
836 break;
837
838 case kTypeString:
839 if (oitem == NULL || *item.u.stringValue != *oitem->u.stringValue) {
840 diff->setString(item.mName, *item.u.stringValue);
841 }
842 break;
843
844 case kTypeRect:
845 if (oitem == NULL || memcmp(&item.u.rectValue, &oitem->u.rectValue, sizeof(Rect))) {
846 diff->setRect(
847 item.mName, item.u.rectValue.mLeft, item.u.rectValue.mTop,
848 item.u.rectValue.mRight, item.u.rectValue.mBottom);
849 }
850 break;
851
852 case kTypePointer:
853 if (oitem == NULL || item.u.ptrValue != oitem->u.ptrValue) {
854 diff->setPointer(item.mName, item.u.ptrValue);
855 }
856 break;
857
858 case kTypeBuffer:
859 {
860 sp<ABuffer> myBuf = static_cast<ABuffer *>(item.u.refValue);
861 if (myBuf == NULL) {
862 if (oitem == NULL || oitem->u.refValue != NULL) {
863 diff->setBuffer(item.mName, NULL);
864 }
865 break;
866 }
867 sp<ABuffer> oBuf = oitem == NULL ? NULL : static_cast<ABuffer *>(oitem->u.refValue);
868 if (oBuf == NULL
869 || myBuf->size() != oBuf->size()
870 || (!myBuf->data() ^ !oBuf->data()) // data nullness differs
871 || (myBuf->data() && memcmp(myBuf->data(), oBuf->data(), myBuf->size()))) {
872 diff->setBuffer(item.mName, myBuf);
873 }
874 break;
875 }
876
877 case kTypeMessage:
878 {
879 sp<AMessage> myMsg = static_cast<AMessage *>(item.u.refValue);
880 if (myMsg == NULL) {
881 if (oitem == NULL || oitem->u.refValue != NULL) {
882 diff->setMessage(item.mName, NULL);
883 }
884 break;
885 }
886 sp<AMessage> oMsg =
887 oitem == NULL ? NULL : static_cast<AMessage *>(oitem->u.refValue);
888 sp<AMessage> changes = myMsg->changesFrom(oMsg, deep);
889 if (changes->countEntries()) {
890 diff->setMessage(item.mName, deep ? changes : myMsg);
891 }
892 break;
893 }
894
895 case kTypeObject:
896 if (oitem == NULL || item.u.refValue != oitem->u.refValue) {
897 diff->setObject(item.mName, item.u.refValue);
898 }
899 break;
900
901 default:
902 {
903 ALOGE("Unknown type %d", item.mType);
904 TRESPASS();
905 }
906 }
907 }
908 return diff;
909 }
910
countEntries() const911 size_t AMessage::countEntries() const {
912 return mNumItems;
913 }
914
getEntryNameAt(size_t index,Type * type) const915 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
916 if (index >= mNumItems) {
917 *type = kTypeInt32;
918
919 return NULL;
920 }
921
922 *type = mItems[index].mType;
923
924 return mItems[index].mName;
925 }
926
927 } // namespace android
928