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 for (size_t i = 0; i < msg->mNumItems; ++i) {
539 Item *item = &msg->mItems[i];
540
541 const char *name = parcel.readCString();
542 item->setName(name, strlen(name));
543 item->mType = static_cast<Type>(parcel.readInt32());
544
545 switch (item->mType) {
546 case kTypeInt32:
547 {
548 item->u.int32Value = parcel.readInt32();
549 break;
550 }
551
552 case kTypeInt64:
553 {
554 item->u.int64Value = parcel.readInt64();
555 break;
556 }
557
558 case kTypeSize:
559 {
560 item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
561 break;
562 }
563
564 case kTypeFloat:
565 {
566 item->u.floatValue = parcel.readFloat();
567 break;
568 }
569
570 case kTypeDouble:
571 {
572 item->u.doubleValue = parcel.readDouble();
573 break;
574 }
575
576 case kTypeString:
577 {
578 item->u.stringValue = new AString(parcel.readCString());
579 break;
580 }
581
582 case kTypeMessage:
583 {
584 sp<AMessage> subMsg = AMessage::FromParcel(parcel);
585 subMsg->incStrong(msg.get());
586
587 item->u.refValue = subMsg.get();
588 break;
589 }
590
591 default:
592 {
593 ALOGE("This type of object cannot cross process boundaries.");
594 TRESPASS();
595 }
596 }
597 }
598
599 return msg;
600 }
601
writeToParcel(Parcel * parcel) const602 void AMessage::writeToParcel(Parcel *parcel) const {
603 parcel->writeInt32(static_cast<int32_t>(mWhat));
604 parcel->writeInt32(static_cast<int32_t>(mNumItems));
605
606 for (size_t i = 0; i < mNumItems; ++i) {
607 const Item &item = mItems[i];
608
609 parcel->writeCString(item.mName);
610 parcel->writeInt32(static_cast<int32_t>(item.mType));
611
612 switch (item.mType) {
613 case kTypeInt32:
614 {
615 parcel->writeInt32(item.u.int32Value);
616 break;
617 }
618
619 case kTypeInt64:
620 {
621 parcel->writeInt64(item.u.int64Value);
622 break;
623 }
624
625 case kTypeSize:
626 {
627 parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
628 break;
629 }
630
631 case kTypeFloat:
632 {
633 parcel->writeFloat(item.u.floatValue);
634 break;
635 }
636
637 case kTypeDouble:
638 {
639 parcel->writeDouble(item.u.doubleValue);
640 break;
641 }
642
643 case kTypeString:
644 {
645 parcel->writeCString(item.u.stringValue->c_str());
646 break;
647 }
648
649 case kTypeMessage:
650 {
651 static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
652 break;
653 }
654
655 default:
656 {
657 ALOGE("This type of object cannot cross process boundaries.");
658 TRESPASS();
659 }
660 }
661 }
662 }
663
countEntries() const664 size_t AMessage::countEntries() const {
665 return mNumItems;
666 }
667
getEntryNameAt(size_t index,Type * type) const668 const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
669 if (index >= mNumItems) {
670 *type = kTypeInt32;
671
672 return NULL;
673 }
674
675 *type = mItems[index].mType;
676
677 return mItems[index].mName;
678 }
679
680 } // namespace android
681