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