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