AMessage.cpp revision bbc2b8289458cfde931b133bad0c9d1026674ee7
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
26namespace android {
27
28AMessage::AMessage(uint32_t what, ALooper::handler_id target)
29    : mWhat(what),
30      mTarget(target),
31      mNumItems(0) {
32}
33
34AMessage::~AMessage() {
35    clear();
36}
37
38void AMessage::setWhat(uint32_t what) {
39    mWhat = what;
40}
41
42uint32_t AMessage::what() const {
43    return mWhat;
44}
45
46void AMessage::setTarget(ALooper::handler_id handlerID) {
47    mTarget = handlerID;
48}
49
50ALooper::handler_id AMessage::target() const {
51    return mTarget;
52}
53
54void AMessage::clear() {
55    for (size_t i = 0; i < mNumItems; ++i) {
56        Item *item = &mItems[i];
57        freeItem(item);
58    }
59    mNumItems = 0;
60}
61
62void AMessage::freeItem(Item *item) {
63    switch (item->mType) {
64        case kTypeString:
65        {
66            delete item->u.stringValue;
67            break;
68        }
69
70        case kTypeObject:
71        case kTypeMessage:
72        {
73            if (item->u.refValue != NULL) {
74                item->u.refValue->decStrong(this);
75            }
76            break;
77        }
78
79        default:
80            break;
81    }
82}
83
84AMessage::Item *AMessage::allocateItem(const char *name) {
85    name = AAtomizer::Atomize(name);
86
87    size_t i = 0;
88    while (i < mNumItems && mItems[i].mName != name) {
89        ++i;
90    }
91
92    Item *item;
93
94    if (i < mNumItems) {
95        item = &mItems[i];
96        freeItem(item);
97    } else {
98        CHECK(mNumItems < kMaxNumItems);
99        i = mNumItems++;
100        item = &mItems[i];
101
102        item->mName = name;
103    }
104
105    return item;
106}
107
108const AMessage::Item *AMessage::findItem(
109        const char *name, Type type) const {
110    name = AAtomizer::Atomize(name);
111
112    for (size_t i = 0; i < mNumItems; ++i) {
113        const Item *item = &mItems[i];
114
115        if (item->mName == name) {
116            return item->mType == type ? item : NULL;
117        }
118    }
119
120    return NULL;
121}
122
123#define BASIC_TYPE(NAME,FIELDNAME,TYPENAME)                             \
124void AMessage::set##NAME(const char *name, TYPENAME value) {            \
125    Item *item = allocateItem(name);                                    \
126                                                                        \
127    item->mType = kType##NAME;                                          \
128    item->u.FIELDNAME = value;                                          \
129}                                                                       \
130                                                                        \
131bool AMessage::find##NAME(const char *name, TYPENAME *value) const {    \
132    const Item *item = findItem(name, kType##NAME);                     \
133    if (item) {                                                         \
134        *value = item->u.FIELDNAME;                                     \
135        return true;                                                    \
136    }                                                                   \
137    return false;                                                       \
138}
139
140BASIC_TYPE(Int32,int32Value,int32_t)
141BASIC_TYPE(Int64,int64Value,int64_t)
142BASIC_TYPE(Size,sizeValue,size_t)
143BASIC_TYPE(Float,floatValue,float)
144BASIC_TYPE(Double,doubleValue,double)
145BASIC_TYPE(Pointer,ptrValue,void *)
146
147#undef BASIC_TYPE
148
149void AMessage::setString(
150        const char *name, const char *s, ssize_t len) {
151    Item *item = allocateItem(name);
152    item->mType = kTypeString;
153    item->u.stringValue = new AString(s, len < 0 ? strlen(s) : len);
154}
155
156void AMessage::setObject(const char *name, const sp<RefBase> &obj) {
157    Item *item = allocateItem(name);
158    item->mType = kTypeObject;
159
160    if (obj != NULL) { obj->incStrong(this); }
161    item->u.refValue = obj.get();
162}
163
164void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
165    Item *item = allocateItem(name);
166    item->mType = kTypeMessage;
167
168    if (obj != NULL) { obj->incStrong(this); }
169    item->u.refValue = obj.get();
170}
171
172bool AMessage::findString(const char *name, AString *value) const {
173    const Item *item = findItem(name, kTypeString);
174    if (item) {
175        *value = *item->u.stringValue;
176        return true;
177    }
178    return false;
179}
180
181bool AMessage::findObject(const char *name, sp<RefBase> *obj) const {
182    const Item *item = findItem(name, kTypeObject);
183    if (item) {
184        *obj = item->u.refValue;
185        return true;
186    }
187    return false;
188}
189
190bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
191    const Item *item = findItem(name, kTypeMessage);
192    if (item) {
193        *obj = static_cast<AMessage *>(item->u.refValue);
194        return true;
195    }
196    return false;
197}
198
199void AMessage::post(int64_t delayUs) {
200    extern ALooperRoster gLooperRoster;
201
202    gLooperRoster.postMessage(this, delayUs);
203}
204
205sp<AMessage> AMessage::dup() const {
206    sp<AMessage> msg = new AMessage(mWhat, mTarget);
207    msg->mNumItems = mNumItems;
208
209    for (size_t i = 0; i < mNumItems; ++i) {
210        const Item *from = &mItems[i];
211        Item *to = &msg->mItems[i];
212
213        to->mName = from->mName;
214        to->mType = from->mType;
215
216        switch (from->mType) {
217            case kTypeString:
218            {
219                to->u.stringValue =
220                    new AString(*from->u.stringValue);
221                break;
222            }
223
224            case kTypeObject:
225            case kTypeMessage:
226            {
227                to->u.refValue = from->u.refValue;
228                to->u.refValue->incStrong(msg.get());
229                break;
230            }
231
232            default:
233            {
234                to->u = from->u;
235                break;
236            }
237        }
238    }
239
240    return msg;
241}
242
243static void appendIndent(AString *s, int32_t indent) {
244    static const char kWhitespace[] =
245        "                                        "
246        "                                        ";
247
248    CHECK_LT((size_t)indent, sizeof(kWhitespace));
249
250    s->append(kWhitespace, indent);
251}
252
253static bool isFourcc(uint32_t what) {
254    return isprint(what & 0xff)
255        && isprint((what >> 8) & 0xff)
256        && isprint((what >> 16) & 0xff)
257        && isprint((what >> 24) & 0xff);
258}
259
260AString AMessage::debugString(int32_t indent) const {
261    AString s = "AMessage(what = ";
262
263    AString tmp;
264    if (isFourcc(mWhat)) {
265        tmp = StringPrintf(
266                "'%c%c%c%c'",
267                (char)(mWhat >> 24),
268                (char)((mWhat >> 16) & 0xff),
269                (char)((mWhat >> 8) & 0xff),
270                (char)(mWhat & 0xff));
271    } else {
272        tmp = StringPrintf("0x%08x", mWhat);
273    }
274    s.append(tmp);
275
276    if (mTarget != 0) {
277        tmp = StringPrintf(", target = %d", mTarget);
278        s.append(tmp);
279    }
280    s.append(") = {\n");
281
282    for (size_t i = 0; i < mNumItems; ++i) {
283        const Item &item = mItems[i];
284
285        switch (item.mType) {
286            case kTypeInt32:
287                tmp = StringPrintf(
288                        "int32_t %s = %d", item.mName, item.u.int32Value);
289                break;
290            case kTypeInt64:
291                tmp = StringPrintf(
292                        "int64_t %s = %lld", item.mName, item.u.int64Value);
293                break;
294            case kTypeSize:
295                tmp = StringPrintf(
296                        "size_t %s = %d", item.mName, item.u.sizeValue);
297                break;
298            case kTypeFloat:
299                tmp = StringPrintf(
300                        "float %s = %f", item.mName, item.u.floatValue);
301                break;
302            case kTypeDouble:
303                tmp = StringPrintf(
304                        "double %s = %f", item.mName, item.u.doubleValue);
305                break;
306            case kTypePointer:
307                tmp = StringPrintf(
308                        "void *%s = %p", item.mName, item.u.ptrValue);
309                break;
310            case kTypeString:
311                tmp = StringPrintf(
312                        "string %s = \"%s\"",
313                        item.mName,
314                        item.u.stringValue->c_str());
315                break;
316            case kTypeObject:
317                tmp = StringPrintf(
318                        "RefBase *%s = %p", item.mName, item.u.refValue);
319                break;
320            case kTypeMessage:
321                tmp = StringPrintf(
322                        "AMessage %s = %s",
323                        item.mName,
324                        static_cast<AMessage *>(
325                            item.u.refValue)->debugString(
326                                indent + strlen(item.mName) + 14).c_str());
327                break;
328            default:
329                TRESPASS();
330        }
331
332        appendIndent(&s, indent);
333        s.append("  ");
334        s.append(tmp);
335        s.append("\n");
336    }
337
338    appendIndent(&s, indent);
339    s.append("}");
340
341    return s;
342}
343
344}  // namespace android
345