blob: 26c6d42ca606b5d42a1e967b8b8149b5d2959e6a [file] [log] [blame]
Andreas Huber7d2f7032010-06-07 10:18:57 -07001/*
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
Andreas Huber03431d22010-07-01 14:11:31 -070019#include <ctype.h>
20
Andreas Huber7d2f7032010-06-07 10:18:57 -070021#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
Andreas Huber03431d22010-07-01 14:11:31 -0700243static 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
Andreas Huber7d2f7032010-06-07 10:18:57 -0700344} // namespace android