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