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