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