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)598 sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
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 for (size_t i = 0; i < msg->mNumItems; ++i) {
605 Item *item = &msg->mItems[i];
606
607 const char *name = parcel.readCString();
608 item->setName(name, strlen(name));
609 item->mType = static_cast<Type>(parcel.readInt32());
610
611 switch (item->mType) {
612 case kTypeInt32:
613 {
614 item->u.int32Value = parcel.readInt32();
615 break;
616 }
617
618 case kTypeInt64:
619 {
620 item->u.int64Value = parcel.readInt64();
621 break;
622 }
623
624 case kTypeSize:
625 {
626 item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
627 break;
628 }
629
630 case kTypeFloat:
631 {
632 item->u.floatValue = parcel.readFloat();
633 break;
634 }
635
636 case kTypeDouble:
637 {
638 item->u.doubleValue = parcel.readDouble();
639 break;
640 }
641
642 case kTypeString:
643 {
644 item->u.stringValue = new AString(parcel.readCString());
645 break;
646 }
647
648 case kTypeMessage:
649 {
650 sp<AMessage> subMsg = AMessage::FromParcel(parcel);
651 subMsg->incStrong(msg.get());
652
653 item->u.refValue = subMsg.get();
654 break;
655 }
656
657 default:
658 {
659 ALOGE("This type of object cannot cross process boundaries.");
660 TRESPASS();
661 }
662 }
663 }
664
665 return msg;
666 }
667
writeToParcel(Parcel * parcel) const668 void AMessage::writeToParcel(Parcel *parcel) const {
669 parcel->writeInt32(static_cast<int32_t>(mWhat));
670 parcel->writeInt32(static_cast<int32_t>(mNumItems));
671
672 for (size_t i = 0; i < mNumItems; ++i) {
673 const Item &item = mItems[i];
674
675 parcel->writeCString(item.mName);
676 parcel->writeInt32(static_cast<int32_t>(item.mType));
677
678 switch (item.mType) {
679 case kTypeInt32:
680 {
681 parcel->writeInt32(item.u.int32Value);
682 break;
683 }
684
685 case kTypeInt64:
686 {
687 parcel->writeInt64(item.u.int64Value);
688 break;
689 }
690
691 case kTypeSize:
692 {
693 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
694 break;
695 }
696
697 case kTypeFloat:
698 {
699 parcel->writeFloat(item.u.floatValue);
700 break;
701 }
702
703 case kTypeDouble:
704 {
705 parcel->writeDouble(item.u.doubleValue);
706 break;
707 }
708
709 case kTypeString:
710 {
711 parcel->writeCString(item.u.stringValue->c_str());
712 break;
713 }
714
715 case kTypeMessage:
716 {
717 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
718 break;
719 }
720
721 default:
722 {
723 ALOGE("This type of object cannot cross process boundaries.");
724 TRESPASS();
725 }
726 }
727 }
728 }
729
countEntries() const730 size_t AMessage::countEntries() const {
731 return mNumItems;
732 }
733
getEntryNameAt(size_t index,Type * type) const734 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
735 if (index >= mNumItems) {
736 *type = kTypeInt32;
737
738 return NULL;
739 }
740
741 *type = mItems[index].mType;
742
743 return mItems[index].mName;
744 }
745
746 } // namespace android
747