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