• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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