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
contains(const char * name) const215 bool AMessage::contains(const char *name) const {
216 size_t i = findItemIndex(name, strlen(name));
217 return i < mNumItems;
218 }
219
220 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \
221 void AMessage::set##NAME(const char *name, TYPENAME value) { \
222 Item *item = allocateItem(name); \
223 \
224 item->mType = kType##NAME; \
225 item->u.FIELDNAME = value; \
226 } \
227 \
228 bool AMessage::find##NAME(const char *name, TYPENAME *value) const { \
229 const Item *item = findItem(name, kType##NAME); \
230 if (item) { \
231 *value = item->u.FIELDNAME; \
232 return true; \
233 } \
234 return false; \
235 }
236
BASIC_TYPE(Int32,int32Value,int32_t)237 BASIC_TYPE(Int32,int32Value,int32_t)
238 BASIC_TYPE(Int64,int64Value,int64_t)
239 BASIC_TYPE(Size,sizeValue,size_t)
240 BASIC_TYPE(Float,floatValue,float)
241 BASIC_TYPE(Double,doubleValue,double)
242 BASIC_TYPE(Pointer,ptrValue,void *)
243
244 #undef BASIC_TYPE
245
246 void AMessage::setString(
247 const char *name, const char *s, ssize_t len) {
248 Item *item = allocateItem(name);
249 item->mType = kTypeString;
250 item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
251 }
252
setString(const char * name,const AString & s)253 void AMessage::setString(
254 const char *name, const AString &s) {
255 setString(name, s.c_str(), s.size());
256 }
257
setObjectInternal(const char * name,const sp<RefBase> & obj,Type type)258 void AMessage::setObjectInternal(
259 const char *name, const sp<RefBase> &obj, Type type) {
260 Item *item = allocateItem(name);
261 item->mType = type;
262
263 if (obj != NULL) { obj->incStrong(this); }
264 item->u.refValue = obj.get();
265 }
266
setObject(const char * name,const sp<RefBase> & obj)267 void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
268 setObjectInternal(name, obj, kTypeObject);
269 }
270
setBuffer(const char * name,const sp<ABuffer> & buffer)271 void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
272 setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
273 }
274
setMessage(const char * name,const sp<AMessage> & obj)275 void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
276 Item *item = allocateItem(name);
277 item->mType = kTypeMessage;
278
279 if (obj != NULL) { obj->incStrong(this); }
280 item->u.refValue = obj.get();
281 }
282
setRect(const char * name,int32_t left,int32_t top,int32_t right,int32_t bottom)283 void AMessage::setRect(
284 const char *name,
285 int32_t left, int32_t top, int32_t right, int32_t bottom) {
286 Item *item = allocateItem(name);
287 item->mType = kTypeRect;
288
289 item->u.rectValue.mLeft = left;
290 item->u.rectValue.mTop = top;
291 item->u.rectValue.mRight = right;
292 item->u.rectValue.mBottom = bottom;
293 }
294
findString(const char * name,AString * value) const295 bool AMessage::findString(const char *name, AString *value) const {
296 const Item *item = findItem(name, kTypeString);
297 if (item) {
298 *value = *item->u.stringValue;
299 return true;
300 }
301 return false;
302 }
303
findObject(const char * name,sp<RefBase> * obj) const304 bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
305 const Item *item = findItem(name, kTypeObject);
306 if (item) {
307 *obj = item->u.refValue;
308 return true;
309 }
310 return false;
311 }
312
findBuffer(const char * name,sp<ABuffer> * buf) const313 bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const {
314 const Item *item = findItem(name, kTypeBuffer);
315 if (item) {
316 *buf = (ABuffer *)(item->u.refValue);
317 return true;
318 }
319 return false;
320 }
321
findMessage(const char * name,sp<AMessage> * obj) const322 bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
323 const Item *item = findItem(name, kTypeMessage);
324 if (item) {
325 *obj = static_cast<AMessage *>(item->u.refValue);
326 return true;
327 }
328 return false;
329 }
330
findRect(const char * name,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const331 bool AMessage::findRect(
332 const char *name,
333 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
334 const Item *item = findItem(name, kTypeRect);
335 if (item == NULL) {
336 return false;
337 }
338
339 *left = item->u.rectValue.mLeft;
340 *top = item->u.rectValue.mTop;
341 *right = item->u.rectValue.mRight;
342 *bottom = item->u.rectValue.mBottom;
343
344 return true;
345 }
346
deliver()347 void AMessage::deliver() {
348 sp<AHandler> handler = mHandler.promote();
349 if (handler == NULL) {
350 ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
351 return;
352 }
353
354 handler->deliverMessage(this);
355 }
356
post(int64_t delayUs)357 status_t AMessage::post(int64_t delayUs) {
358 sp<ALooper> looper = mLooper.promote();
359 if (looper == NULL) {
360 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
361 return -ENOENT;
362 }
363
364 looper->post(this, delayUs);
365 return OK;
366 }
367
postAndAwaitResponse(sp<AMessage> * response)368 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
369 sp<ALooper> looper = mLooper.promote();
370 if (looper == NULL) {
371 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
372 return -ENOENT;
373 }
374
375 sp<AReplyToken> token = looper->createReplyToken();
376 if (token == NULL) {
377 ALOGE("failed to create reply token");
378 return -ENOMEM;
379 }
380 setObject("replyID", token);
381
382 looper->post(this, 0 /* delayUs */);
383 return looper->awaitResponse(token, response);
384 }
385
postReply(const sp<AReplyToken> & replyToken)386 status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
387 if (replyToken == NULL) {
388 ALOGW("failed to post reply to a NULL token");
389 return -ENOENT;
390 }
391 sp<ALooper> looper = replyToken->getLooper();
392 if (looper == NULL) {
393 ALOGW("failed to post reply as target looper is gone.");
394 return -ENOENT;
395 }
396 return looper->postReply(replyToken, this);
397 }
398
senderAwaitsResponse(sp<AReplyToken> * replyToken)399 bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
400 sp<RefBase> tmp;
401 bool found = findObject("replyID", &tmp);
402
403 if (!found) {
404 return false;
405 }
406
407 *replyToken = static_cast<AReplyToken *>(tmp.get());
408 tmp.clear();
409 setObject("replyID", tmp);
410 // TODO: delete Object instead of setting it to NULL
411
412 return *replyToken != NULL;
413 }
414
dup() const415 sp<AMessage> AMessage::dup() const {
416 sp<AMessage> msg = new AMessage(mWhat, mHandler.promote());
417 msg->mNumItems = mNumItems;
418
419 #ifdef DUMP_STATS
420 {
421 Mutex::Autolock _l(gLock);
422 ++gDupCalls;
423 gAverageDupItems += mNumItems;
424 reportStats();
425 }
426 #endif
427
428 for (size_t i = 0; i < mNumItems; ++i) {
429 const Item *from = &mItems[i];
430 Item *to = &msg->mItems[i];
431
432 to->setName(from->mName, from->mNameLength);
433 to->mType = from->mType;
434
435 switch (from->mType) {
436 case kTypeString:
437 {
438 to->u.stringValue =
439 new AString(*from->u.stringValue);
440 break;
441 }
442
443 case kTypeObject:
444 case kTypeBuffer:
445 {
446 to->u.refValue = from->u.refValue;
447 to->u.refValue->incStrong(msg.get());
448 break;
449 }
450
451 case kTypeMessage:
452 {
453 sp<AMessage> copy =
454 static_cast<AMessage *>(from->u.refValue)->dup();
455
456 to->u.refValue = copy.get();
457 to->u.refValue->incStrong(msg.get());
458 break;
459 }
460
461 default:
462 {
463 to->u = from->u;
464 break;
465 }
466 }
467 }
468
469 return msg;
470 }
471
appendIndent(AString * s,int32_t indent)472 static void appendIndent(AString *s, int32_t indent) {
473 static const char kWhitespace[] =
474 " "
475 " ";
476
477 CHECK_LT((size_t)indent, sizeof(kWhitespace));
478
479 s->append(kWhitespace, indent);
480 }
481
isFourcc(uint32_t what)482 static bool isFourcc(uint32_t what) {
483 return isprint(what & 0xff)
484 && isprint((what >> 8) & 0xff)
485 && isprint((what >> 16) & 0xff)
486 && isprint((what >> 24) & 0xff);
487 }
488
debugString(int32_t indent) const489 AString AMessage::debugString(int32_t indent) const {
490 AString s = "AMessage(what = ";
491
492 AString tmp;
493 if (isFourcc(mWhat)) {
494 tmp = AStringPrintf(
495 "'%c%c%c%c'",
496 (char)(mWhat >> 24),
497 (char)((mWhat >> 16) & 0xff),
498 (char)((mWhat >> 8) & 0xff),
499 (char)(mWhat & 0xff));
500 } else {
501 tmp = AStringPrintf("0x%08x", mWhat);
502 }
503 s.append(tmp);
504
505 if (mTarget != 0) {
506 tmp = AStringPrintf(", target = %d", mTarget);
507 s.append(tmp);
508 }
509 s.append(") = {\n");
510
511 for (size_t i = 0; i < mNumItems; ++i) {
512 const Item &item = mItems[i];
513
514 switch (item.mType) {
515 case kTypeInt32:
516 tmp = AStringPrintf(
517 "int32_t %s = %d", item.mName, item.u.int32Value);
518 break;
519 case kTypeInt64:
520 tmp = AStringPrintf(
521 "int64_t %s = %lld", item.mName, item.u.int64Value);
522 break;
523 case kTypeSize:
524 tmp = AStringPrintf(
525 "size_t %s = %d", item.mName, item.u.sizeValue);
526 break;
527 case kTypeFloat:
528 tmp = AStringPrintf(
529 "float %s = %f", item.mName, item.u.floatValue);
530 break;
531 case kTypeDouble:
532 tmp = AStringPrintf(
533 "double %s = %f", item.mName, item.u.doubleValue);
534 break;
535 case kTypePointer:
536 tmp = AStringPrintf(
537 "void *%s = %p", item.mName, item.u.ptrValue);
538 break;
539 case kTypeString:
540 tmp = AStringPrintf(
541 "string %s = \"%s\"",
542 item.mName,
543 item.u.stringValue->c_str());
544 break;
545 case kTypeObject:
546 tmp = AStringPrintf(
547 "RefBase *%s = %p", item.mName, item.u.refValue);
548 break;
549 case kTypeBuffer:
550 {
551 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
552
553 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
554 tmp = AStringPrintf("Buffer %s = {\n", item.mName);
555 hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
556 appendIndent(&tmp, indent + 2);
557 tmp.append("}");
558 } else {
559 tmp = AStringPrintf(
560 "Buffer *%s = %p", item.mName, buffer.get());
561 }
562 break;
563 }
564 case kTypeMessage:
565 tmp = AStringPrintf(
566 "AMessage %s = %s",
567 item.mName,
568 static_cast<AMessage *>(
569 item.u.refValue)->debugString(
570 indent + strlen(item.mName) + 14).c_str());
571 break;
572 case kTypeRect:
573 tmp = AStringPrintf(
574 "Rect %s(%d, %d, %d, %d)",
575 item.mName,
576 item.u.rectValue.mLeft,
577 item.u.rectValue.mTop,
578 item.u.rectValue.mRight,
579 item.u.rectValue.mBottom);
580 break;
581 default:
582 TRESPASS();
583 }
584
585 appendIndent(&s, indent);
586 s.append(" ");
587 s.append(tmp);
588 s.append("\n");
589 }
590
591 appendIndent(&s, indent);
592 s.append("}");
593
594 return s;
595 }
596
597 // static
FromParcel(const Parcel & parcel,size_t maxNestingLevel)598 sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) {
599 int32_t what = parcel.readInt32();
600 sp<AMessage> msg = new AMessage();
601 msg->setWhat(what);
602
603 msg->mNumItems = static_cast<size_t>(parcel.readInt32());
604 if (msg->mNumItems > kMaxNumItems) {
605 ALOGE("Too large number of items clipped.");
606 msg->mNumItems = kMaxNumItems;
607 }
608
609 for (size_t i = 0; i < msg->mNumItems; ++i) {
610 Item *item = &msg->mItems[i];
611
612 const char *name = parcel.readCString();
613 if (name == NULL) {
614 ALOGE("Failed reading name for an item. Parsing aborted.");
615 msg->mNumItems = i;
616 break;
617 }
618
619 item->mType = static_cast<Type>(parcel.readInt32());
620 // setName() happens below so that we don't leak memory when parsing
621 // is aborted in the middle.
622 switch (item->mType) {
623 case kTypeInt32:
624 {
625 item->u.int32Value = parcel.readInt32();
626 break;
627 }
628
629 case kTypeInt64:
630 {
631 item->u.int64Value = parcel.readInt64();
632 break;
633 }
634
635 case kTypeSize:
636 {
637 item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
638 break;
639 }
640
641 case kTypeFloat:
642 {
643 item->u.floatValue = parcel.readFloat();
644 break;
645 }
646
647 case kTypeDouble:
648 {
649 item->u.doubleValue = parcel.readDouble();
650 break;
651 }
652
653 case kTypeString:
654 {
655 const char *stringValue = parcel.readCString();
656 if (stringValue == NULL) {
657 ALOGE("Failed reading string value from a parcel. "
658 "Parsing aborted.");
659 msg->mNumItems = i;
660 continue;
661 // The loop will terminate subsequently.
662 } else {
663 item->u.stringValue = new AString(stringValue);
664 }
665 break;
666 }
667
668 case kTypeMessage:
669 {
670 if (maxNestingLevel == 0) {
671 ALOGE("Too many levels of AMessage nesting.");
672 return NULL;
673 }
674 sp<AMessage> subMsg = AMessage::FromParcel(
675 parcel,
676 maxNestingLevel - 1);
677 if (subMsg == NULL) {
678 // This condition will be triggered when there exists an
679 // object that cannot cross process boundaries or when the
680 // level of nested AMessage is too deep.
681 return NULL;
682 }
683 subMsg->incStrong(msg.get());
684
685 item->u.refValue = subMsg.get();
686 break;
687 }
688
689 default:
690 {
691 ALOGE("This type of object cannot cross process boundaries.");
692 return NULL;
693 }
694 }
695
696 item->setName(name, strlen(name));
697 }
698
699 return msg;
700 }
701
writeToParcel(Parcel * parcel) const702 void AMessage::writeToParcel(Parcel *parcel) const {
703 parcel->writeInt32(static_cast<int32_t>(mWhat));
704 parcel->writeInt32(static_cast<int32_t>(mNumItems));
705
706 for (size_t i = 0; i < mNumItems; ++i) {
707 const Item &item = mItems[i];
708
709 parcel->writeCString(item.mName);
710 parcel->writeInt32(static_cast<int32_t>(item.mType));
711
712 switch (item.mType) {
713 case kTypeInt32:
714 {
715 parcel->writeInt32(item.u.int32Value);
716 break;
717 }
718
719 case kTypeInt64:
720 {
721 parcel->writeInt64(item.u.int64Value);
722 break;
723 }
724
725 case kTypeSize:
726 {
727 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
728 break;
729 }
730
731 case kTypeFloat:
732 {
733 parcel->writeFloat(item.u.floatValue);
734 break;
735 }
736
737 case kTypeDouble:
738 {
739 parcel->writeDouble(item.u.doubleValue);
740 break;
741 }
742
743 case kTypeString:
744 {
745 parcel->writeCString(item.u.stringValue->c_str());
746 break;
747 }
748
749 case kTypeMessage:
750 {
751 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
752 break;
753 }
754
755 default:
756 {
757 ALOGE("This type of object cannot cross process boundaries.");
758 TRESPASS();
759 }
760 }
761 }
762 }
763
changesFrom(const sp<const AMessage> & other,bool deep) const764 sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const {
765 if (other == NULL) {
766 return const_cast<AMessage*>(this);
767 }
768
769 sp<AMessage> diff = new AMessage;
770 if (mWhat != other->mWhat) {
771 diff->setWhat(mWhat);
772 }
773 if (mHandler != other->mHandler) {
774 diff->setTarget(mHandler.promote());
775 }
776
777 for (size_t i = 0; i < mNumItems; ++i) {
778 const Item &item = mItems[i];
779 const Item *oitem = other->findItem(item.mName, item.mType);
780 switch (item.mType) {
781 case kTypeInt32:
782 if (oitem == NULL || item.u.int32Value != oitem->u.int32Value) {
783 diff->setInt32(item.mName, item.u.int32Value);
784 }
785 break;
786
787 case kTypeInt64:
788 if (oitem == NULL || item.u.int64Value != oitem->u.int64Value) {
789 diff->setInt64(item.mName, item.u.int64Value);
790 }
791 break;
792
793 case kTypeSize:
794 if (oitem == NULL || item.u.sizeValue != oitem->u.sizeValue) {
795 diff->setSize(item.mName, item.u.sizeValue);
796 }
797 break;
798
799 case kTypeFloat:
800 if (oitem == NULL || item.u.floatValue != oitem->u.floatValue) {
801 diff->setFloat(item.mName, item.u.sizeValue);
802 }
803 break;
804
805 case kTypeDouble:
806 if (oitem == NULL || item.u.doubleValue != oitem->u.doubleValue) {
807 diff->setDouble(item.mName, item.u.sizeValue);
808 }
809 break;
810
811 case kTypeString:
812 if (oitem == NULL || *item.u.stringValue != *oitem->u.stringValue) {
813 diff->setString(item.mName, *item.u.stringValue);
814 }
815 break;
816
817 case kTypeRect:
818 if (oitem == NULL || memcmp(&item.u.rectValue, &oitem->u.rectValue, sizeof(Rect))) {
819 diff->setRect(
820 item.mName, item.u.rectValue.mLeft, item.u.rectValue.mTop,
821 item.u.rectValue.mRight, item.u.rectValue.mBottom);
822 }
823 break;
824
825 case kTypePointer:
826 if (oitem == NULL || item.u.ptrValue != oitem->u.ptrValue) {
827 diff->setPointer(item.mName, item.u.ptrValue);
828 }
829 break;
830
831 case kTypeBuffer:
832 {
833 sp<ABuffer> myBuf = static_cast<ABuffer *>(item.u.refValue);
834 if (myBuf == NULL) {
835 if (oitem == NULL || oitem->u.refValue != NULL) {
836 diff->setBuffer(item.mName, NULL);
837 }
838 break;
839 }
840 sp<ABuffer> oBuf = oitem == NULL ? NULL : static_cast<ABuffer *>(oitem->u.refValue);
841 if (oBuf == NULL
842 || myBuf->size() != oBuf->size()
843 || (!myBuf->data() ^ !oBuf->data()) // data nullness differs
844 || (myBuf->data() && memcmp(myBuf->data(), oBuf->data(), myBuf->size()))) {
845 diff->setBuffer(item.mName, myBuf);
846 }
847 break;
848 }
849
850 case kTypeMessage:
851 {
852 sp<AMessage> myMsg = static_cast<AMessage *>(item.u.refValue);
853 if (myMsg == NULL) {
854 if (oitem == NULL || oitem->u.refValue != NULL) {
855 diff->setMessage(item.mName, NULL);
856 }
857 break;
858 }
859 sp<AMessage> oMsg =
860 oitem == NULL ? NULL : static_cast<AMessage *>(oitem->u.refValue);
861 sp<AMessage> changes = myMsg->changesFrom(oMsg, deep);
862 if (changes->countEntries()) {
863 diff->setMessage(item.mName, deep ? changes : myMsg);
864 }
865 break;
866 }
867
868 case kTypeObject:
869 if (oitem == NULL || item.u.refValue != oitem->u.refValue) {
870 diff->setObject(item.mName, item.u.refValue);
871 }
872 break;
873
874 default:
875 {
876 ALOGE("Unknown type %d", item.mType);
877 TRESPASS();
878 }
879 }
880 }
881 return diff;
882 }
883
countEntries() const884 size_t AMessage::countEntries() const {
885 return mNumItems;
886 }
887
getEntryNameAt(size_t index,Type * type) const888 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
889 if (index >= mNumItems) {
890 *type = kTypeInt32;
891
892 return NULL;
893 }
894
895 *type = mItems[index].mType;
896
897 return mItems[index].mName;
898 }
899
900 } // namespace android
901