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