AMessage.cpp revision 183d387706417863076873ec566ca5966d8f5560
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
40status_t AReplyToken::setReply(const sp<AMessage> &reply) {
41    if (mReplied) {
42        ALOGE("trying to post a duplicate reply");
43        return -EBUSY;
44    }
45    CHECK(mReply == NULL);
46    mReply = reply;
47    mReplied = true;
48    return OK;
49}
50
51AMessage::AMessage(void)
52    : mWhat(0),
53      mTarget(0),
54      mNumItems(0) {
55}
56
57AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
58    : mWhat(what),
59      mNumItems(0) {
60    setTarget(handler);
61}
62
63AMessage::~AMessage() {
64    clear();
65}
66
67void AMessage::setWhat(uint32_t what) {
68    mWhat = what;
69}
70
71uint32_t AMessage::what() const {
72    return mWhat;
73}
74
75void AMessage::setTarget(const sp<const AHandler> &handler) {
76    if (handler == NULL) {
77        mTarget = 0;
78        mHandler.clear();
79        mLooper.clear();
80    } else {
81        mTarget = handler->id();
82        mHandler = handler->getHandler();
83        mLooper = handler->getLooper();
84    }
85}
86
87void AMessage::clear() {
88    for (size_t i = 0; i < mNumItems; ++i) {
89        Item *item = &mItems[i];
90        delete[] item->mName;
91        item->mName = NULL;
92        freeItemValue(item);
93    }
94    mNumItems = 0;
95}
96
97void AMessage::freeItemValue(Item *item) {
98    switch (item->mType) {
99        case kTypeString:
100        {
101            delete item->u.stringValue;
102            break;
103        }
104
105        case kTypeObject:
106        case kTypeMessage:
107        case kTypeBuffer:
108        {
109            if (item->u.refValue != NULL) {
110                item->u.refValue->decStrong(this);
111            }
112            break;
113        }
114
115        default:
116            break;
117    }
118}
119
120#ifdef DUMP_STATS
121#include <utils/Mutex.h>
122
123Mutex gLock;
124static int32_t gFindItemCalls = 1;
125static int32_t gDupCalls = 1;
126static int32_t gAverageNumItems = 0;
127static int32_t gAverageNumChecks = 0;
128static int32_t gAverageNumMemChecks = 0;
129static int32_t gAverageDupItems = 0;
130static int32_t gLastChecked = -1;
131
132static void reportStats() {
133    int32_t time = (ALooper::GetNowUs() / 1000);
134    if (time / 1000 != gLastChecked / 1000) {
135        gLastChecked = time;
136        ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)",
137                gFindItemCalls,
138                gAverageNumItems / (float)gFindItemCalls,
139                gAverageNumChecks / (float)gFindItemCalls,
140                gAverageNumMemChecks / (float)gFindItemCalls,
141                gDupCalls,
142                gAverageDupItems / (float)gDupCalls);
143        gFindItemCalls = gDupCalls = 1;
144        gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0;
145        gLastChecked = time;
146    }
147}
148#endif
149
150inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
151#ifdef DUMP_STATS
152    size_t memchecks = 0;
153#endif
154    size_t i = 0;
155    for (; i < mNumItems; i++) {
156        if (len != mItems[i].mNameLength) {
157            continue;
158        }
159#ifdef DUMP_STATS
160        ++memchecks;
161#endif
162        if (!memcmp(mItems[i].mName, name, len)) {
163            break;
164        }
165    }
166#ifdef DUMP_STATS
167    {
168        Mutex::Autolock _l(gLock);
169        ++gFindItemCalls;
170        gAverageNumItems += mNumItems;
171        gAverageNumMemChecks += memchecks;
172        gAverageNumChecks += i;
173        reportStats();
174    }
175#endif
176    return i;
177}
178
179// assumes item's name was uninitialized or NULL
180void AMessage::Item::setName(const char *name, size_t len) {
181    mNameLength = len;
182    mName = new char[len + 1];
183    memcpy((void*)mName, name, len + 1);
184}
185
186AMessage::Item *AMessage::allocateItem(const char *name) {
187    size_t len = strlen(name);
188    size_t i = findItemIndex(name, len);
189    Item *item;
190
191    if (i < mNumItems) {
192        item = &mItems[i];
193        freeItemValue(item);
194    } else {
195        CHECK(mNumItems < kMaxNumItems);
196        i = mNumItems++;
197        item = &mItems[i];
198        item->setName(name, len);
199    }
200
201    return item;
202}
203
204const AMessage::Item *AMessage::findItem(
205        const char *name, Type type) const {
206    size_t i = findItemIndex(name, strlen(name));
207    if (i < mNumItems) {
208        const Item *item = &mItems[i];
209        return item->mType == type ? item : NULL;
210
211    }
212    return NULL;
213}
214
215bool AMessage::contains(const char *name) const {
216    size_t i = findItemIndex(name, strlen(name));
217    return i < mNumItems;
218}
219
220#define BASIC_TYPE(NAME,FIELDNAME,TYPENAME)                             \
221void AMessage::set##NAME(const char *name, TYPENAME value) {            \
222    Item *item = allocateItem(name);                                    \
223                                                                        \
224    item->mType = kType##NAME;                                          \
225    item->u.FIELDNAME = value;                                          \
226}                                                                       \
227                                                                        \
228/* NOLINT added to avoid incorrect warning/fix from clang.tidy */       \
229bool AMessage::find##NAME(const char *name, TYPENAME *value) const {  /* NOLINT */ \
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    sp<ALooper> looper = mLooper.promote();
371    if (looper == NULL) {
372        ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
373        return -ENOENT;
374    }
375
376    sp<AReplyToken> token = looper->createReplyToken();
377    if (token == NULL) {
378        ALOGE("failed to create reply token");
379        return -ENOMEM;
380    }
381    setObject("replyID", token);
382
383    looper->post(this, 0 /* delayUs */);
384    return looper->awaitResponse(token, response);
385}
386
387status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
388    if (replyToken == NULL) {
389        ALOGW("failed to post reply to a NULL token");
390        return -ENOENT;
391    }
392    sp<ALooper> looper = replyToken->getLooper();
393    if (looper == NULL) {
394        ALOGW("failed to post reply as target looper is gone.");
395        return -ENOENT;
396    }
397    return looper->postReply(replyToken, this);
398}
399
400bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
401    sp<RefBase> tmp;
402    bool found = findObject("replyID", &tmp);
403
404    if (!found) {
405        return false;
406    }
407
408    *replyToken = static_cast<AReplyToken *>(tmp.get());
409    tmp.clear();
410    setObject("replyID", tmp);
411    // TODO: delete Object instead of setting it to NULL
412
413    return *replyToken != NULL;
414}
415
416sp<AMessage> AMessage::dup() const {
417    sp<AMessage> msg = new AMessage(mWhat, mHandler.promote());
418    msg->mNumItems = mNumItems;
419
420#ifdef DUMP_STATS
421    {
422        Mutex::Autolock _l(gLock);
423        ++gDupCalls;
424        gAverageDupItems += mNumItems;
425        reportStats();
426    }
427#endif
428
429    for (size_t i = 0; i < mNumItems; ++i) {
430        const Item *from = &mItems[i];
431        Item *to = &msg->mItems[i];
432
433        to->setName(from->mName, from->mNameLength);
434        to->mType = from->mType;
435
436        switch (from->mType) {
437            case kTypeString:
438            {
439                to->u.stringValue =
440                    new AString(*from->u.stringValue);
441                break;
442            }
443
444            case kTypeObject:
445            case kTypeBuffer:
446            {
447                to->u.refValue = from->u.refValue;
448                to->u.refValue->incStrong(msg.get());
449                break;
450            }
451
452            case kTypeMessage:
453            {
454                sp<AMessage> copy =
455                    static_cast<AMessage *>(from->u.refValue)->dup();
456
457                to->u.refValue = copy.get();
458                to->u.refValue->incStrong(msg.get());
459                break;
460            }
461
462            default:
463            {
464                to->u = from->u;
465                break;
466            }
467        }
468    }
469
470    return msg;
471}
472
473static void appendIndent(AString *s, int32_t indent) {
474    static const char kWhitespace[] =
475        "                                        "
476        "                                        ";
477
478    CHECK_LT((size_t)indent, sizeof(kWhitespace));
479
480    s->append(kWhitespace, indent);
481}
482
483static bool isFourcc(uint32_t what) {
484    return isprint(what & 0xff)
485        && isprint((what >> 8) & 0xff)
486        && isprint((what >> 16) & 0xff)
487        && isprint((what >> 24) & 0xff);
488}
489
490AString AMessage::debugString(int32_t indent) const {
491    AString s = "AMessage(what = ";
492
493    AString tmp;
494    if (isFourcc(mWhat)) {
495        tmp = AStringPrintf(
496                "'%c%c%c%c'",
497                (char)(mWhat >> 24),
498                (char)((mWhat >> 16) & 0xff),
499                (char)((mWhat >> 8) & 0xff),
500                (char)(mWhat & 0xff));
501    } else {
502        tmp = AStringPrintf("0x%08x", mWhat);
503    }
504    s.append(tmp);
505
506    if (mTarget != 0) {
507        tmp = AStringPrintf(", target = %d", mTarget);
508        s.append(tmp);
509    }
510    s.append(") = {\n");
511
512    for (size_t i = 0; i < mNumItems; ++i) {
513        const Item &item = mItems[i];
514
515        switch (item.mType) {
516            case kTypeInt32:
517                tmp = AStringPrintf(
518                        "int32_t %s = %d", item.mName, item.u.int32Value);
519                break;
520            case kTypeInt64:
521                tmp = AStringPrintf(
522                        "int64_t %s = %lld", item.mName, item.u.int64Value);
523                break;
524            case kTypeSize:
525                tmp = AStringPrintf(
526                        "size_t %s = %d", item.mName, item.u.sizeValue);
527                break;
528            case kTypeFloat:
529                tmp = AStringPrintf(
530                        "float %s = %f", item.mName, item.u.floatValue);
531                break;
532            case kTypeDouble:
533                tmp = AStringPrintf(
534                        "double %s = %f", item.mName, item.u.doubleValue);
535                break;
536            case kTypePointer:
537                tmp = AStringPrintf(
538                        "void *%s = %p", item.mName, item.u.ptrValue);
539                break;
540            case kTypeString:
541                tmp = AStringPrintf(
542                        "string %s = \"%s\"",
543                        item.mName,
544                        item.u.stringValue->c_str());
545                break;
546            case kTypeObject:
547                tmp = AStringPrintf(
548                        "RefBase *%s = %p", item.mName, item.u.refValue);
549                break;
550            case kTypeBuffer:
551            {
552                sp<ABuffer> buffer = static_cast<ABuffer *>(item.u.refValue);
553
554                if (buffer != NULL && buffer->data() != NULL && buffer->size() <= 64) {
555                    tmp = AStringPrintf("Buffer %s = {\n", item.mName);
556                    hexdump(buffer->data(), buffer->size(), indent + 4, &tmp);
557                    appendIndent(&tmp, indent + 2);
558                    tmp.append("}");
559                } else {
560                    tmp = AStringPrintf(
561                            "Buffer *%s = %p", item.mName, buffer.get());
562                }
563                break;
564            }
565            case kTypeMessage:
566                tmp = AStringPrintf(
567                        "AMessage %s = %s",
568                        item.mName,
569                        static_cast<AMessage *>(
570                            item.u.refValue)->debugString(
571                                indent + strlen(item.mName) + 14).c_str());
572                break;
573            case kTypeRect:
574                tmp = AStringPrintf(
575                        "Rect %s(%d, %d, %d, %d)",
576                        item.mName,
577                        item.u.rectValue.mLeft,
578                        item.u.rectValue.mTop,
579                        item.u.rectValue.mRight,
580                        item.u.rectValue.mBottom);
581                break;
582            default:
583                TRESPASS();
584        }
585
586        appendIndent(&s, indent);
587        s.append("  ");
588        s.append(tmp);
589        s.append("\n");
590    }
591
592    appendIndent(&s, indent);
593    s.append("}");
594
595    return s;
596}
597
598// static
599sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
600    int32_t what = parcel.readInt32();
601    sp<AMessage> msg = new AMessage();
602    msg->setWhat(what);
603
604    msg->mNumItems = static_cast<size_t>(parcel.readInt32());
605    if (msg->mNumItems > kMaxNumItems) {
606        ALOGE("Too large number of items clipped.");
607        msg->mNumItems = kMaxNumItems;
608    }
609
610    for (size_t i = 0; i < msg->mNumItems; ++i) {
611        Item *item = &msg->mItems[i];
612
613        const char *name = parcel.readCString();
614        if (name == NULL) {
615            ALOGE("Failed reading name for an item. Parsing aborted.");
616            msg->mNumItems = i;
617            break;
618        }
619
620        item->mType = static_cast<Type>(parcel.readInt32());
621        // setName() happens below so that we don't leak memory when parsing
622        // is aborted in the middle.
623        switch (item->mType) {
624            case kTypeInt32:
625            {
626                item->u.int32Value = parcel.readInt32();
627                break;
628            }
629
630            case kTypeInt64:
631            {
632                item->u.int64Value = parcel.readInt64();
633                break;
634            }
635
636            case kTypeSize:
637            {
638                item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
639                break;
640            }
641
642            case kTypeFloat:
643            {
644                item->u.floatValue = parcel.readFloat();
645                break;
646            }
647
648            case kTypeDouble:
649            {
650                item->u.doubleValue = parcel.readDouble();
651                break;
652            }
653
654            case kTypeString:
655            {
656                const char *stringValue = parcel.readCString();
657                if (stringValue == NULL) {
658                    ALOGE("Failed reading string value from a parcel. "
659                        "Parsing aborted.");
660                    msg->mNumItems = i;
661                    continue;
662                    // The loop will terminate subsequently.
663                } else {
664                    item->u.stringValue = new AString(stringValue);
665                }
666                break;
667            }
668
669            case kTypeMessage:
670            {
671                sp<AMessage> subMsg = AMessage::FromParcel(parcel);
672                subMsg->incStrong(msg.get());
673
674                item->u.refValue = subMsg.get();
675                break;
676            }
677
678            default:
679            {
680                ALOGE("This type of object cannot cross process boundaries.");
681                TRESPASS();
682            }
683        }
684
685        item->setName(name, strlen(name));
686    }
687
688    return msg;
689}
690
691void AMessage::writeToParcel(Parcel *parcel) const {
692    parcel->writeInt32(static_cast<int32_t>(mWhat));
693    parcel->writeInt32(static_cast<int32_t>(mNumItems));
694
695    for (size_t i = 0; i < mNumItems; ++i) {
696        const Item &item = mItems[i];
697
698        parcel->writeCString(item.mName);
699        parcel->writeInt32(static_cast<int32_t>(item.mType));
700
701        switch (item.mType) {
702            case kTypeInt32:
703            {
704                parcel->writeInt32(item.u.int32Value);
705                break;
706            }
707
708            case kTypeInt64:
709            {
710                parcel->writeInt64(item.u.int64Value);
711                break;
712            }
713
714            case kTypeSize:
715            {
716                parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
717                break;
718            }
719
720            case kTypeFloat:
721            {
722                parcel->writeFloat(item.u.floatValue);
723                break;
724            }
725
726            case kTypeDouble:
727            {
728                parcel->writeDouble(item.u.doubleValue);
729                break;
730            }
731
732            case kTypeString:
733            {
734                parcel->writeCString(item.u.stringValue->c_str());
735                break;
736            }
737
738            case kTypeMessage:
739            {
740                static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
741                break;
742            }
743
744            default:
745            {
746                ALOGE("This type of object cannot cross process boundaries.");
747                TRESPASS();
748            }
749        }
750    }
751}
752
753size_t AMessage::countEntries() const {
754    return mNumItems;
755}
756
757const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
758    if (index >= mNumItems) {
759        *type = kTypeInt32;
760
761        return NULL;
762    }
763
764    *type = mItems[index].mType;
765
766    return mItems[index].mName;
767}
768
769}  // namespace android
770