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