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