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