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 "AString.h"
31
32 #include <binder/Parcel.h>
33 #include <media/stagefright/foundation/hexdump.h>
34
35 namespace android {
36
37 extern ALooperRoster gLooperRoster;
38
AMessage(uint32_t what,ALooper::handler_id target)39 AMessage::AMessage(uint32_t what, ALooper::handler_id target)
40 : mWhat(what),
41 mTarget(target),
42 mNumItems(0) {
43 }
44
~AMessage()45 AMessage::~AMessage() {
46 clear();
47 }
48
setWhat(uint32_t what)49 void AMessage::setWhat(uint32_t what) {
50 mWhat = what;
51 }
52
what() const53 uint32_t AMessage::what() const {
54 return mWhat;
55 }
56
setTarget(ALooper::handler_id handlerID)57 void AMessage::setTarget(ALooper::handler_id handlerID) {
58 mTarget = handlerID;
59 }
60
target() const61 ALooper::handler_id AMessage::target() const {
62 return mTarget;
63 }
64
clear()65 void AMessage::clear() {
66 for (size_t i = 0; i < mNumItems; ++i) {
67 Item *item = &mItems[i];
68 delete[] item->mName;
69 item->mName = NULL;
70 freeItemValue(item);
71 }
72 mNumItems = 0;
73 }
74
freeItemValue(Item * item)75 void AMessage::freeItemValue(Item *item) {
76 switch (item->mType) {
77 case kTypeString:
78 {
79 delete item->u.stringValue;
80 break;
81 }
82
83 case kTypeObject:
84 case kTypeMessage:
85 case kTypeBuffer:
86 {
87 if (item->u.refValue != NULL) {
88 item->u.refValue->decStrong(this);
89 }
90 break;
91 }
92
93 default:
94 break;
95 }
96 }
97
98 #ifdef DUMP_STATS
99 #include <utils/Mutex.h>
100
101 Mutex gLock;
102 static int32_t gFindItemCalls = 1;
103 static int32_t gDupCalls = 1;
104 static int32_t gAverageNumItems = 0;
105 static int32_t gAverageNumChecks = 0;
106 static int32_t gAverageNumMemChecks = 0;
107 static int32_t gAverageDupItems = 0;
108 static int32_t gLastChecked = -1;
109
reportStats()110 static void reportStats() {
111 int32_t time = (ALooper::GetNowUs() / 1000);
112 if (time / 1000 != gLastChecked / 1000) {
113 gLastChecked = time;
114 ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)",
115 gFindItemCalls,
116 gAverageNumItems / (float)gFindItemCalls,
117 gAverageNumChecks / (float)gFindItemCalls,
118 gAverageNumMemChecks / (float)gFindItemCalls,
119 gDupCalls,
120 gAverageDupItems / (float)gDupCalls);
121 gFindItemCalls = gDupCalls = 1;
122 gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0;
123 gLastChecked = time;
124 }
125 }
126 #endif
127
findItemIndex(const char * name,size_t len) const128 inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
129 #ifdef DUMP_STATS
130 size_t memchecks = 0;
131 #endif
132 size_t i = 0;
133 for (; i < mNumItems; i++) {
134 if (len != mItems[i].mNameLength) {
135 continue;
136 }
137 #ifdef DUMP_STATS
138 ++memchecks;
139 #endif
140 if (!memcmp(mItems[i].mName, name, len)) {
141 break;
142 }
143 }
144 #ifdef DUMP_STATS
145 {
146 Mutex::Autolock _l(gLock);
147 ++gFindItemCalls;
148 gAverageNumItems += mNumItems;
149 gAverageNumMemChecks += memchecks;
150 gAverageNumChecks += i;
151 reportStats();
152 }
153 #endif
154 return i;
155 }
156
157 // assumes item's name was uninitialized or NULL
setName(const char * name,size_t len)158 void AMessage::Item::setName(const char *name, size_t len) {
159 mNameLength = len;
160 mName = new char[len + 1];
161 memcpy((void*)mName, name, len + 1);
162 }
163
allocateItem(const char * name)164 AMessage::Item *AMessage::allocateItem(const char *name) {
165 size_t len = strlen(name);
166 size_t i = findItemIndex(name, len);
167 Item *item;
168
169 if (i < mNumItems) {
170 item = &mItems[i];
171 freeItemValue(item);
172 } else {
173 CHECK(mNumItems < kMaxNumItems);
174 i = mNumItems++;
175 item = &mItems[i];
176 item->setName(name, len);
177 }
178
179 return item;
180 }
181
findItem(const char * name,Type type) const182 const AMessage::Item *AMessage::findItem(
183 const char *name, Type type) const {
184 size_t i = findItemIndex(name, strlen(name));
185 if (i < mNumItems) {
186 const Item *item = &mItems[i];
187 return item->mType == type ? item : NULL;
188
189 }
190 return NULL;
191 }
192
contains(const char * name) const193 bool AMessage::contains(const char *name) const {
194 size_t i = findItemIndex(name, strlen(name));
195 return i < mNumItems;
196 }
197
198 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME) \
199 void AMessage::set##NAME(const char *name, TYPENAME value) { \
200 Item *item = allocateItem(name); \
201 \
202 item->mType = kType##NAME; \
203 item->u.FIELDNAME = value; \
204 } \
205 \
206 bool AMessage::find##NAME(const char *name, TYPENAME *value) const { \
207 const Item *item = findItem(name, kType##NAME); \
208 if (item) { \
209 *value = item->u.FIELDNAME; \
210 return true; \
211 } \
212 return false; \
213 }
214
BASIC_TYPE(Int32,int32Value,int32_t)215 BASIC_TYPE(Int32,int32Value,int32_t)
216 BASIC_TYPE(Int64,int64Value,int64_t)
217 BASIC_TYPE(Size,sizeValue,size_t)
218 BASIC_TYPE(Float,floatValue,float)
219 BASIC_TYPE(Double,doubleValue,double)
220 BASIC_TYPE(Pointer,ptrValue,void *)
221
222 #undef BASIC_TYPE
223
224 void AMessage::setString(
225 const char *name, const char *s, ssize_t len) {
226 Item *item = allocateItem(name);
227 item->mType = kTypeString;
228 item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
229 }
230
setString(const char * name,const AString & s)231 void AMessage::setString(
232 const char *name, const AString &s) {
233 setString(name, s.c_str(), s.size());
234 }
235
setObjectInternal(const char * name,const sp<RefBase> & obj,Type type)236 void AMessage::setObjectInternal(
237 const char *name, const sp<RefBase> &obj, Type type) {
238 Item *item = allocateItem(name);
239 item->mType = type;
240
241 if (obj != NULL) { obj->incStrong(this); }
242 item->u.refValue = obj.get();
243 }
244
setObject(const char * name,const sp<RefBase> & obj)245 void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
246 setObjectInternal(name, obj, kTypeObject);
247 }
248
setBuffer(const char * name,const sp<ABuffer> & buffer)249 void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
250 setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
251 }
252
setMessage(const char * name,const sp<AMessage> & obj)253 void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
254 Item *item = allocateItem(name);
255 item->mType = kTypeMessage;
256
257 if (obj != NULL) { obj->incStrong(this); }
258 item->u.refValue = obj.get();
259 }
260
setRect(const char * name,int32_t left,int32_t top,int32_t right,int32_t bottom)261 void AMessage::setRect(
262 const char *name,
263 int32_t left, int32_t top, int32_t right, int32_t bottom) {
264 Item *item = allocateItem(name);
265 item->mType = kTypeRect;
266
267 item->u.rectValue.mLeft = left;
268 item->u.rectValue.mTop = top;
269 item->u.rectValue.mRight = right;
270 item->u.rectValue.mBottom = bottom;
271 }
272
findString(const char * name,AString * value) const273 bool AMessage::findString(const char *name, AString *value) const {
274 const Item *item = findItem(name, kTypeString);
275 if (item) {
276 *value = *item->u.stringValue;
277 return true;
278 }
279 return false;
280 }
281
findObject(const char * name,sp<RefBase> * obj) const282 bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
283 const Item *item = findItem(name, kTypeObject);
284 if (item) {
285 *obj = item->u.refValue;
286 return true;
287 }
288 return false;
289 }
290
findBuffer(const char * name,sp<ABuffer> * buf) const291 bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const {
292 const Item *item = findItem(name, kTypeBuffer);
293 if (item) {
294 *buf = (ABuffer *)(item->u.refValue);
295 return true;
296 }
297 return false;
298 }
299
findMessage(const char * name,sp<AMessage> * obj) const300 bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
301 const Item *item = findItem(name, kTypeMessage);
302 if (item) {
303 *obj = static_cast<AMessage *>(item->u.refValue);
304 return true;
305 }
306 return false;
307 }
308
findRect(const char * name,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const309 bool AMessage::findRect(
310 const char *name,
311 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
312 const Item *item = findItem(name, kTypeRect);
313 if (item == NULL) {
314 return false;
315 }
316
317 *left = item->u.rectValue.mLeft;
318 *top = item->u.rectValue.mTop;
319 *right = item->u.rectValue.mRight;
320 *bottom = item->u.rectValue.mBottom;
321
322 return true;
323 }
324
post(int64_t delayUs)325 void AMessage::post(int64_t delayUs) {
326 gLooperRoster.postMessage(this, delayUs);
327 }
328
postAndAwaitResponse(sp<AMessage> * response)329 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
330 return gLooperRoster.postAndAwaitResponse(this, response);
331 }
332
postReply(uint32_t replyID)333 void AMessage::postReply(uint32_t replyID) {
334 gLooperRoster.postReply(replyID, this);
335 }
336
senderAwaitsResponse(uint32_t * replyID) const337 bool AMessage::senderAwaitsResponse(uint32_t *replyID) const {
338 int32_t tmp;
339 bool found = findInt32("replyID", &tmp);
340
341 if (!found) {
342 return false;
343 }
344
345 *replyID = static_cast<uint32_t>(tmp);
346
347 return true;
348 }
349
dup() const350 sp<AMessage> AMessage::dup() const {
351 sp<AMessage> msg = new AMessage(mWhat, mTarget);
352 msg->mNumItems = mNumItems;
353
354 #ifdef DUMP_STATS
355 {
356 Mutex::Autolock _l(gLock);
357 ++gDupCalls;
358 gAverageDupItems += mNumItems;
359 reportStats();
360 }
361 #endif
362
363 for (size_t i = 0; i < mNumItems; ++i) {
364 const Item *from = &mItems[i];
365 Item *to = &msg->mItems[i];
366
367 to->setName(from->mName, from->mNameLength);
368 to->mType = from->mType;
369
370 switch (from->mType) {
371 case kTypeString:
372 {
373 to->u.stringValue =
374 new AString(*from->u.stringValue);
375 break;
376 }
377
378 case kTypeObject:
379 case kTypeBuffer:
380 {
381 to->u.refValue = from->u.refValue;
382 to->u.refValue->incStrong(msg.get());
383 break;
384 }
385
386 case kTypeMessage:
387 {
388 sp<AMessage> copy =
389 static_cast<AMessage *>(from->u.refValue)->dup();
390
391 to->u.refValue = copy.get();
392 to->u.refValue->incStrong(msg.get());
393 break;
394 }
395
396 default:
397 {
398 to->u = from->u;
399 break;
400 }
401 }
402 }
403
404 return msg;
405 }
406
appendIndent(AString * s,int32_t indent)407 static void appendIndent(AString *s, int32_t indent) {
408 static const char kWhitespace[] =
409 " "
410 " ";
411
412 CHECK_LT((size_t)indent, sizeof(kWhitespace));
413
414 s->append(kWhitespace, indent);
415 }
416
isFourcc(uint32_t what)417 static bool isFourcc(uint32_t what) {
418 return isprint(what & 0xff)
419 && isprint((what >> 8) & 0xff)
420 && isprint((what >> 16) & 0xff)
421 && isprint((what >> 24) & 0xff);
422 }
423
debugString(int32_t indent) const424 AString AMessage::debugString(int32_t indent) const {
425 AString s = "AMessage(what = ";
426
427 AString tmp;
428 if (isFourcc(mWhat)) {
429 tmp = StringPrintf(
430 "'%c%c%c%c'",
431 (char)(mWhat >> 24),
432 (char)((mWhat >> 16) & 0xff),
433 (char)((mWhat >> 8) & 0xff),
434 (char)(mWhat & 0xff));
435 } else {
436 tmp = StringPrintf("0x%08x", mWhat);
437 }
438 s.append(tmp);
439
440 if (mTarget != 0) {
441 tmp = StringPrintf(", target = %d", mTarget);
442 s.append(tmp);
443 }
444 s.append(") = {\n");
445
446 for (size_t i = 0; i < mNumItems; ++i) {
447 const Item &item = mItems[i];
448
449 switch (item.mType) {
450 case kTypeInt32:
451 tmp = StringPrintf(
452 "int32_t %s = %d", item.mName, item.u.int32Value);
453 break;
454 case kTypeInt64:
455 tmp = StringPrintf(
456 "int64_t %s = %lld", item.mName, item.u.int64Value);
457 break;
458 case kTypeSize:
459 tmp = StringPrintf(
460 "size_t %s = %d", item.mName, item.u.sizeValue);
461 break;
462 case kTypeFloat:
463 tmp = StringPrintf(
464 "float %s = %f", item.mName, item.u.floatValue);
465 break;
466 case kTypeDouble:
467 tmp = StringPrintf(
468 "double %s = %f", item.mName, item.u.doubleValue);
469 break;
470 case kTypePointer:
471 tmp = StringPrintf(
472 "void *%s = %p", item.mName, item.u.ptrValue);
473 break;
474 case kTypeString:
475 tmp = StringPrintf(
476 "string %s = \"%s\"",
477 item.mName,
478 item.u.stringValue->c_str());
479 break;
480 case kTypeObject:
481 tmp = StringPrintf(
482 "RefBase *%s = %p", item.mName, item.u.refValue);
483 break;
484 case kTypeBuffer:
485 {
486 sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
487
488 if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
489 tmp = StringPrintf("Buffer %s = {\n", item.mName);
490 hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
491 appendIndent(&tmp, indent + 2);
492 tmp.append("}");
493 } else {
494 tmp = StringPrintf(
495 "Buffer *%s = %p", item.mName, buffer.get());
496 }
497 break;
498 }
499 case kTypeMessage:
500 tmp = StringPrintf(
501 "AMessage %s = %s",
502 item.mName,
503 static_cast<AMessage *>(
504 item.u.refValue)->debugString(
505 indent + strlen(item.mName) + 14).c_str());
506 break;
507 case kTypeRect:
508 tmp = StringPrintf(
509 "Rect %s(%d, %d, %d, %d)",
510 item.mName,
511 item.u.rectValue.mLeft,
512 item.u.rectValue.mTop,
513 item.u.rectValue.mRight,
514 item.u.rectValue.mBottom);
515 break;
516 default:
517 TRESPASS();
518 }
519
520 appendIndent(&s, indent);
521 s.append(" ");
522 s.append(tmp);
523 s.append("\n");
524 }
525
526 appendIndent(&s, indent);
527 s.append("}");
528
529 return s;
530 }
531
532 // static
FromParcel(const Parcel & parcel)533 sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
534 int32_t what = parcel.readInt32();
535 sp<AMessage> msg = new AMessage(what);
536
537 msg->mNumItems = static_cast<size_t>(parcel.readInt32());
538 if (msg->mNumItems > kMaxNumItems) {
539 ALOGE("Too large number of items clipped.");
540 msg->mNumItems = kMaxNumItems;
541 }
542
543 for (size_t i = 0; i < msg->mNumItems; ++i) {
544 Item *item = &msg->mItems[i];
545
546 const char *name = parcel.readCString();
547 if (name == NULL) {
548 ALOGE("Failed reading name for an item. Parsing aborted.");
549 msg->mNumItems = i;
550 break;
551 }
552
553 item->mType = static_cast<Type>(parcel.readInt32());
554 // setName() happens below so that we don't leak memory when parsing
555 // is aborted in the middle.
556 switch (item->mType) {
557 case kTypeInt32:
558 {
559 item->u.int32Value = parcel.readInt32();
560 break;
561 }
562
563 case kTypeInt64:
564 {
565 item->u.int64Value = parcel.readInt64();
566 break;
567 }
568
569 case kTypeSize:
570 {
571 item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
572 break;
573 }
574
575 case kTypeFloat:
576 {
577 item->u.floatValue = parcel.readFloat();
578 break;
579 }
580
581 case kTypeDouble:
582 {
583 item->u.doubleValue = parcel.readDouble();
584 break;
585 }
586
587 case kTypeString:
588 {
589 const char *stringValue = parcel.readCString();
590 if (stringValue == NULL) {
591 ALOGE("Failed reading string value from a parcel. "
592 "Parsing aborted.");
593 msg->mNumItems = i;
594 continue;
595 // The loop will terminate subsequently.
596 } else {
597 item->u.stringValue = new AString(stringValue);
598 }
599 break;
600 }
601
602 case kTypeMessage:
603 {
604 sp<AMessage> subMsg = AMessage::FromParcel(parcel);
605 subMsg->incStrong(msg.get());
606
607 item->u.refValue = subMsg.get();
608 break;
609 }
610
611 default:
612 {
613 ALOGE("This type of object cannot cross process boundaries.");
614 TRESPASS();
615 }
616 }
617
618 item->setName(name, strlen(name));
619 }
620
621 return msg;
622 }
623
writeToParcel(Parcel * parcel) const624 void AMessage::writeToParcel(Parcel *parcel) const {
625 parcel->writeInt32(static_cast<int32_t>(mWhat));
626 parcel->writeInt32(static_cast<int32_t>(mNumItems));
627
628 for (size_t i = 0; i < mNumItems; ++i) {
629 const Item &item = mItems[i];
630
631 parcel->writeCString(item.mName);
632 parcel->writeInt32(static_cast<int32_t>(item.mType));
633
634 switch (item.mType) {
635 case kTypeInt32:
636 {
637 parcel->writeInt32(item.u.int32Value);
638 break;
639 }
640
641 case kTypeInt64:
642 {
643 parcel->writeInt64(item.u.int64Value);
644 break;
645 }
646
647 case kTypeSize:
648 {
649 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
650 break;
651 }
652
653 case kTypeFloat:
654 {
655 parcel->writeFloat(item.u.floatValue);
656 break;
657 }
658
659 case kTypeDouble:
660 {
661 parcel->writeDouble(item.u.doubleValue);
662 break;
663 }
664
665 case kTypeString:
666 {
667 parcel->writeCString(item.u.stringValue->c_str());
668 break;
669 }
670
671 case kTypeMessage:
672 {
673 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
674 break;
675 }
676
677 default:
678 {
679 ALOGE("This type of object cannot cross process boundaries.");
680 TRESPASS();
681 }
682 }
683 }
684 }
685
countEntries() const686 size_t AMessage::countEntries() const {
687 return mNumItems;
688 }
689
getEntryNameAt(size_t index,Type * type) const690 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
691 if (index >= mNumItems) {
692 *type = kTypeInt32;
693
694 return NULL;
695 }
696
697 *type = mItems[index].mType;
698
699 return mItems[index].mName;
700 }
701
702 } // namespace android
703