AMessage.cpp revision 7ea429295a2eb31f2d9256c36c1ef53a195456ac
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
35namespace android {
36
37extern ALooperRoster gLooperRoster;
38
39AMessage::AMessage(uint32_t what, ALooper::handler_id target)
40    : mWhat(what),
41      mTarget(target),
42      mNumItems(0) {
43}
44
45AMessage::~AMessage() {
46    clear();
47}
48
49void AMessage::setWhat(uint32_t what) {
50    mWhat = what;
51}
52
53uint32_t AMessage::what() const {
54    return mWhat;
55}
56
57void AMessage::setTarget(ALooper::handler_id handlerID) {
58    mTarget = handlerID;
59}
60
61ALooper::handler_id AMessage::target() const {
62    return mTarget;
63}
64
65void 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
75void 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
101Mutex gLock;
102static int32_t gFindItemCalls = 1;
103static int32_t gDupCalls = 1;
104static int32_t gAverageNumItems = 0;
105static int32_t gAverageNumChecks = 0;
106static int32_t gAverageNumMemChecks = 0;
107static int32_t gAverageDupItems = 0;
108static int32_t gLastChecked = -1;
109
110static 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
128inline 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
158void 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
164AMessage::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
182const 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
193bool 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)                             \
199void 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                                                                        \
206bool 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
215BASIC_TYPE(Int32,int32Value,int32_t)
216BASIC_TYPE(Int64,int64Value,int64_t)
217BASIC_TYPE(Size,sizeValue,size_t)
218BASIC_TYPE(Float,floatValue,float)
219BASIC_TYPE(Double,doubleValue,double)
220BASIC_TYPE(Pointer,ptrValue,void *)
221
222#undef BASIC_TYPE
223
224void 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
231void AMessage::setString(
232        const char *name, const AString &s) {
233    setString(name, s.c_str(), s.size());
234}
235
236void 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
245void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
246    setObjectInternal(name, obj, kTypeObject);
247}
248
249void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
250    setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
251}
252
253void 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
261void 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
273bool 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
282bool 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
291bool 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
300bool 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
309bool 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
325void AMessage::post(int64_t delayUs) {
326    gLooperRoster.postMessage(this, delayUs);
327}
328
329status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
330    return gLooperRoster.postAndAwaitResponse(this, response);
331}
332
333void AMessage::postReply(uint32_t replyID) {
334    gLooperRoster.postReply(replyID, this);
335}
336
337bool 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
350sp<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
407static 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
417static 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
424AString 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->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
533sp<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
602void 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
664size_t AMessage::countEntries() const {
665    return mNumItems;
666}
667
668const 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