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_NDEBUG 0
     18 #define LOG_TAG "ALooperRoster"
     19 #include <utils/Log.h>
     20 
     21 #include "ALooperRoster.h"
     22 
     23 #include "ADebug.h"
     24 #include "AHandler.h"
     25 #include "AMessage.h"
     26 
     27 namespace android {
     28 
     29 ALooperRoster::ALooperRoster()
     30     : mNextHandlerID(1),
     31       mNextReplyID(1) {
     32 }
     33 
     34 ALooper::handler_id ALooperRoster::registerHandler(
     35         const sp<ALooper> looper, const sp<AHandler> &handler) {
     36     Mutex::Autolock autoLock(mLock);
     37 
     38     if (handler->id() != 0) {
     39         CHECK(!"A handler must only be registered once.");
     40         return INVALID_OPERATION;
     41     }
     42 
     43     HandlerInfo info;
     44     info.mLooper = looper;
     45     info.mHandler = handler;
     46     ALooper::handler_id handlerID = mNextHandlerID++;
     47     mHandlers.add(handlerID, info);
     48 
     49     handler->setID(handlerID);
     50 
     51     return handlerID;
     52 }
     53 
     54 void ALooperRoster::unregisterHandler(ALooper::handler_id handlerID) {
     55     Mutex::Autolock autoLock(mLock);
     56 
     57     ssize_t index = mHandlers.indexOfKey(handlerID);
     58 
     59     if (index < 0) {
     60         return;
     61     }
     62 
     63     const HandlerInfo &info = mHandlers.valueAt(index);
     64 
     65     sp<AHandler> handler = info.mHandler.promote();
     66 
     67     if (handler != NULL) {
     68         handler->setID(0);
     69     }
     70 
     71     mHandlers.removeItemsAt(index);
     72 }
     73 
     74 void ALooperRoster::unregisterStaleHandlers() {
     75 
     76     Vector<sp<ALooper> > activeLoopers;
     77     {
     78         Mutex::Autolock autoLock(mLock);
     79 
     80         for (size_t i = mHandlers.size(); i-- > 0;) {
     81             const HandlerInfo &info = mHandlers.valueAt(i);
     82 
     83             sp<ALooper> looper = info.mLooper.promote();
     84             if (looper == NULL) {
     85                 ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
     86                 mHandlers.removeItemsAt(i);
     87             } else {
     88                 // At this point 'looper' might be the only sp<> keeping
     89                 // the object alive. To prevent it from going out of scope
     90                 // and having ~ALooper call this method again recursively
     91                 // and then deadlocking because of the Autolock above, add
     92                 // it to a Vector which will go out of scope after the lock
     93                 // has been released.
     94                 activeLoopers.add(looper);
     95             }
     96         }
     97     }
     98 }
     99 
    100 status_t ALooperRoster::postMessage(
    101         const sp<AMessage> &msg, int64_t delayUs) {
    102 
    103     sp<ALooper> looper = findLooper(msg->target());
    104 
    105     if (looper == NULL) {
    106         return -ENOENT;
    107     }
    108     looper->post(msg, delayUs);
    109     return OK;
    110 }
    111 
    112 void ALooperRoster::deliverMessage(const sp<AMessage> &msg) {
    113     sp<AHandler> handler;
    114 
    115     {
    116         Mutex::Autolock autoLock(mLock);
    117 
    118         ssize_t index = mHandlers.indexOfKey(msg->target());
    119 
    120         if (index < 0) {
    121             ALOGW("failed to deliver message. Target handler not registered.");
    122             return;
    123         }
    124 
    125         const HandlerInfo &info = mHandlers.valueAt(index);
    126         handler = info.mHandler.promote();
    127 
    128         if (handler == NULL) {
    129             ALOGW("failed to deliver message. "
    130                  "Target handler %d registered, but object gone.",
    131                  msg->target());
    132 
    133             mHandlers.removeItemsAt(index);
    134             return;
    135         }
    136     }
    137 
    138     handler->onMessageReceived(msg);
    139 }
    140 
    141 sp<ALooper> ALooperRoster::findLooper(ALooper::handler_id handlerID) {
    142     Mutex::Autolock autoLock(mLock);
    143 
    144     ssize_t index = mHandlers.indexOfKey(handlerID);
    145 
    146     if (index < 0) {
    147         return NULL;
    148     }
    149 
    150     sp<ALooper> looper = mHandlers.valueAt(index).mLooper.promote();
    151 
    152     if (looper == NULL) {
    153         mHandlers.removeItemsAt(index);
    154         return NULL;
    155     }
    156 
    157     return looper;
    158 }
    159 
    160 status_t ALooperRoster::postAndAwaitResponse(
    161         const sp<AMessage> &msg, sp<AMessage> *response) {
    162     sp<ALooper> looper = findLooper(msg->target());
    163 
    164     if (looper == NULL) {
    165         ALOGW("failed to post message. "
    166                 "Target handler %d still registered, but object gone.",
    167                 msg->target());
    168         response->clear();
    169         return -ENOENT;
    170     }
    171 
    172     Mutex::Autolock autoLock(mLock);
    173 
    174     uint32_t replyID = mNextReplyID++;
    175 
    176     msg->setInt32("replyID", replyID);
    177 
    178     looper->post(msg, 0 /* delayUs */);
    179 
    180     ssize_t index;
    181     while ((index = mReplies.indexOfKey(replyID)) < 0) {
    182         mRepliesCondition.wait(mLock);
    183     }
    184 
    185     *response = mReplies.valueAt(index);
    186     mReplies.removeItemsAt(index);
    187 
    188     return OK;
    189 }
    190 
    191 void ALooperRoster::postReply(uint32_t replyID, const sp<AMessage> &reply) {
    192     Mutex::Autolock autoLock(mLock);
    193 
    194     CHECK(mReplies.indexOfKey(replyID) < 0);
    195     mReplies.add(replyID, reply);
    196     mRepliesCondition.broadcast();
    197 }
    198 
    199 }  // namespace android
    200