• 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     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