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