AMessage.cpp revision 31e2508c75018145a8238925ff1a08cbde4e799a
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
174void AMessage::setRect(
175        const char *name,
176        int32_t left, int32_t top, int32_t right, int32_t bottom) {
177    Item *item = allocateItem(name);
178    item->mType = kTypeRect;
179
180    item->u.rectValue.mLeft = left;
181    item->u.rectValue.mTop = top;
182    item->u.rectValue.mRight = right;
183    item->u.rectValue.mBottom = bottom;
184}
185
186bool AMessage::findString(const char *name, AString *value) const {
187    const Item *item = findItem(name, kTypeString);
188    if (item) {
189        *value = *item->u.stringValue;
190        return true;
191    }
192    return false;
193}
194
195bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
196    const Item *item = findItem(name, kTypeObject);
197    if (item) {
198        *obj = item->u.refValue;
199        return true;
200    }
201    return false;
202}
203
204bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
205    const Item *item = findItem(name, kTypeMessage);
206    if (item) {
207        *obj = static_cast<AMessage *>(item->u.refValue);
208        return true;
209    }
210    return false;
211}
212
213bool AMessage::findRect(
214        const char *name,
215        int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const {
216    const Item *item = findItem(name, kTypeRect);
217    if (item == NULL) {
218        return false;
219    }
220
221    *left = item->u.rectValue.mLeft;
222    *top = item->u.rectValue.mTop;
223    *right = item->u.rectValue.mRight;
224    *bottom = item->u.rectValue.mBottom;
225
226    return true;
227}
228
229void AMessage::post(int64_t delayUs) {
230    extern ALooperRoster gLooperRoster;
231
232    gLooperRoster.postMessage(this, delayUs);
233}
234
235sp<AMessage> AMessage::dup() const {
236    sp<AMessage> msg = new AMessage(mWhat, mTarget);
237    msg->mNumItems = mNumItems;
238
239    for (size_t i = 0; i < mNumItems; ++i) {
240        const Item *from = &mItems[i];
241        Item *to = &msg->mItems[i];
242
243        to->mName = from->mName;
244        to->mType = from->mType;
245
246        switch (from->mType) {
247            case kTypeString:
248            {
249                to->u.stringValue =
250                    new AString(*from->u.stringValue);
251                break;
252            }
253
254            case kTypeObject:
255            {
256                to->u.refValue = from->u.refValue;
257                to->u.refValue->incStrong(msg.get());
258                break;
259            }
260
261            case kTypeMessage:
262            {
263                sp<AMessage> copy =
264                    static_cast<AMessage *>(from->u.refValue)->dup();
265
266                to->u.refValue = copy.get();
267                to->u.refValue->incStrong(msg.get());
268                break;
269            }
270
271            default:
272            {
273                to->u = from->u;
274                break;
275            }
276        }
277    }
278
279    return msg;
280}
281
282static void appendIndent(AString *s, int32_t indent) {
283    static const char kWhitespace[] =
284        "                                        "
285        "                                        ";
286
287    CHECK_LT((size_t)indent, sizeof(kWhitespace));
288
289    s->append(kWhitespace, indent);
290}
291
292static bool isFourcc(uint32_t what) {
293    return isprint(what & 0xff)
294        && isprint((what >> 8) & 0xff)
295        && isprint((what >> 16) & 0xff)
296        && isprint((what >> 24) & 0xff);
297}
298
299AString AMessage::debugString(int32_t indent) const {
300    AString s = "AMessage(what = ";
301
302    AString tmp;
303    if (isFourcc(mWhat)) {
304        tmp = StringPrintf(
305                "'%c%c%c%c'",
306                (char)(mWhat >> 24),
307                (char)((mWhat >> 16) & 0xff),
308                (char)((mWhat >> 8) & 0xff),
309                (char)(mWhat & 0xff));
310    } else {
311        tmp = StringPrintf("0x%08x", mWhat);
312    }
313    s.append(tmp);
314
315    if (mTarget != 0) {
316        tmp = StringPrintf(", target = %d", mTarget);
317        s.append(tmp);
318    }
319    s.append(") = {\n");
320
321    for (size_t i = 0; i < mNumItems; ++i) {
322        const Item &item = mItems[i];
323
324        switch (item.mType) {
325            case kTypeInt32:
326                tmp = StringPrintf(
327                        "int32_t %s = %d", item.mName, item.u.int32Value);
328                break;
329            case kTypeInt64:
330                tmp = StringPrintf(
331                        "int64_t %s = %lld", item.mName, item.u.int64Value);
332                break;
333            case kTypeSize:
334                tmp = StringPrintf(
335                        "size_t %s = %d", item.mName, item.u.sizeValue);
336                break;
337            case kTypeFloat:
338                tmp = StringPrintf(
339                        "float %s = %f", item.mName, item.u.floatValue);
340                break;
341            case kTypeDouble:
342                tmp = StringPrintf(
343                        "double %s = %f", item.mName, item.u.doubleValue);
344                break;
345            case kTypePointer:
346                tmp = StringPrintf(
347                        "void *%s = %p", item.mName, item.u.ptrValue);
348                break;
349            case kTypeString:
350                tmp = StringPrintf(
351                        "string %s = \"%s\"",
352                        item.mName,
353                        item.u.stringValue->c_str());
354                break;
355            case kTypeObject:
356                tmp = StringPrintf(
357                        "RefBase *%s = %p", item.mName, item.u.refValue);
358                break;
359            case kTypeMessage:
360                tmp = StringPrintf(
361                        "AMessage %s = %s",
362                        item.mName,
363                        static_cast<AMessage *>(
364                            item.u.refValue)->debugString(
365                                indent + strlen(item.mName) + 14).c_str());
366                break;
367            default:
368                TRESPASS();
369        }
370
371        appendIndent(&s, indent);
372        s.append("  ");
373        s.append(tmp);
374        s.append("\n");
375    }
376
377    appendIndent(&s, indent);
378    s.append("}");
379
380    return s;
381}
382
383// static
384sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
385    int32_t what = parcel.readInt32();
386    sp<AMessage> msg = new AMessage(what);
387
388    msg->mNumItems = static_cast<size_t>(parcel.readInt32());
389
390    for (size_t i = 0; i < msg->mNumItems; ++i) {
391        Item *item = &msg->mItems[i];
392
393        item->mName = AAtomizer::Atomize(parcel.readCString());
394        item->mType = static_cast<Type>(parcel.readInt32());
395
396        switch (item->mType) {
397            case kTypeInt32:
398            {
399                item->u.int32Value = parcel.readInt32();
400                break;
401            }
402
403            case kTypeInt64:
404            {
405                item->u.int64Value = parcel.readInt64();
406                break;
407            }
408
409            case kTypeSize:
410            {
411                item->u.sizeValue = static_cast<size_t>(parcel.readInt32());
412                break;
413            }
414
415            case kTypeFloat:
416            {
417                item->u.floatValue = parcel.readFloat();
418                break;
419            }
420
421            case kTypeDouble:
422            {
423                item->u.doubleValue = parcel.readDouble();
424                break;
425            }
426
427            case kTypeString:
428            {
429                item->u.stringValue = new AString(parcel.readCString());
430                break;
431            }
432
433            case kTypeMessage:
434            {
435                sp<AMessage> subMsg = AMessage::FromParcel(parcel);
436                subMsg->incStrong(msg.get());
437
438                item->u.refValue = subMsg.get();
439                break;
440            }
441
442            default:
443            {
444                LOGE("This type of object cannot cross process boundaries.");
445                TRESPASS();
446            }
447        }
448    }
449
450    return msg;
451}
452
453void AMessage::writeToParcel(Parcel *parcel) const {
454    parcel->writeInt32(static_cast<int32_t>(mWhat));
455    parcel->writeInt32(static_cast<int32_t>(mNumItems));
456
457    for (size_t i = 0; i < mNumItems; ++i) {
458        const Item &item = mItems[i];
459
460        parcel->writeCString(item.mName);
461        parcel->writeInt32(static_cast<int32_t>(item.mType));
462
463        switch (item.mType) {
464            case kTypeInt32:
465            {
466                parcel->writeInt32(item.u.int32Value);
467                break;
468            }
469
470            case kTypeInt64:
471            {
472                parcel->writeInt64(item.u.int64Value);
473                break;
474            }
475
476            case kTypeSize:
477            {
478                parcel->writeInt32(static_cast<int32_t>(item.u.sizeValue));
479                break;
480            }
481
482            case kTypeFloat:
483            {
484                parcel->writeFloat(item.u.floatValue);
485                break;
486            }
487
488            case kTypeDouble:
489            {
490                parcel->writeDouble(item.u.doubleValue);
491                break;
492            }
493
494            case kTypeString:
495            {
496                parcel->writeCString(item.u.stringValue->c_str());
497                break;
498            }
499
500            case kTypeMessage:
501            {
502                static_cast<AMessage *>(item.u.refValue)->writeToParcel(parcel);
503                break;
504            }
505
506            default:
507            {
508                LOGE("This type of object cannot cross process boundaries.");
509                TRESPASS();
510            }
511        }
512    }
513}
514
515}  // namespace android
516