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 "ALooper"
     19 
     20 #include <media/stagefright/foundation/ADebug.h>
     21 
     22 #include <utils/Log.h>
     23 
     24 #include <sys/time.h>
     25 
     26 #include "ALooper.h"
     27 
     28 #include "AHandler.h"
     29 #include "ALooperRoster.h"
     30 #include "AMessage.h"
     31 
     32 namespace android {
     33 
     34 ALooperRoster gLooperRoster;
     35 
     36 struct ALooper::LooperThread : public Thread {
     37     LooperThread(ALooper *looper, bool canCallJava)
     38         : Thread(canCallJava),
     39           mLooper(looper),
     40           mThreadId(NULL) {
     41     }
     42 
     43     virtual status_t readyToRun() {
     44         mThreadId = androidGetThreadId();
     45 
     46         return Thread::readyToRun();
     47     }
     48 
     49     virtual bool threadLoop() {
     50         return mLooper->loop();
     51     }
     52 
     53     bool isCurrentThread() const {
     54         return mThreadId == androidGetThreadId();
     55     }
     56 
     57 protected:
     58     virtual ~LooperThread() {}
     59 
     60 private:
     61     ALooper *mLooper;
     62     android_thread_id_t mThreadId;
     63 
     64     DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
     65 };
     66 
     67 // static
     68 int64_t ALooper::GetNowUs() {
     69     return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;
     70 }
     71 
     72 ALooper::ALooper()
     73     : mRunningLocally(false) {
     74     // clean up stale AHandlers. Doing it here instead of in the destructor avoids
     75     // the side effect of objects being deleted from the unregister function recursively.
     76     gLooperRoster.unregisterStaleHandlers();
     77 }
     78 
     79 ALooper::~ALooper() {
     80     stop();
     81     // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along
     82 }
     83 
     84 void ALooper::setName(const char *name) {
     85     mName = name;
     86 }
     87 
     88 ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
     89     return gLooperRoster.registerHandler(this, handler);
     90 }
     91 
     92 void ALooper::unregisterHandler(handler_id handlerID) {
     93     gLooperRoster.unregisterHandler(handlerID);
     94 }
     95 
     96 status_t ALooper::start(
     97         bool runOnCallingThread, bool canCallJava, int32_t priority) {
     98     if (runOnCallingThread) {
     99         {
    100             Mutex::Autolock autoLock(mLock);
    101 
    102             if (mThread != NULL || mRunningLocally) {
    103                 return INVALID_OPERATION;
    104             }
    105 
    106             mRunningLocally = true;
    107         }
    108 
    109         do {
    110         } while (loop());
    111 
    112         return OK;
    113     }
    114 
    115     Mutex::Autolock autoLock(mLock);
    116 
    117     if (mThread != NULL || mRunningLocally) {
    118         return INVALID_OPERATION;
    119     }
    120 
    121     mThread = new LooperThread(this, canCallJava);
    122 
    123     status_t err = mThread->run(
    124             mName.empty() ? "ALooper" : mName.c_str(), priority);
    125     if (err != OK) {
    126         mThread.clear();
    127     }
    128 
    129     return err;
    130 }
    131 
    132 status_t ALooper::stop() {
    133     sp<LooperThread> thread;
    134     bool runningLocally;
    135 
    136     {
    137         Mutex::Autolock autoLock(mLock);
    138 
    139         thread = mThread;
    140         runningLocally = mRunningLocally;
    141         mThread.clear();
    142         mRunningLocally = false;
    143     }
    144 
    145     if (thread == NULL && !runningLocally) {
    146         return INVALID_OPERATION;
    147     }
    148 
    149     if (thread != NULL) {
    150         thread->requestExit();
    151     }
    152 
    153     mQueueChangedCondition.signal();
    154     {
    155         Mutex::Autolock autoLock(mRepliesLock);
    156         mRepliesCondition.broadcast();
    157     }
    158 
    159     if (!runningLocally && !thread->isCurrentThread()) {
    160         // If not running locally and this thread _is_ the looper thread,
    161         // the loop() function will return and never be called again.
    162         thread->requestExitAndWait();
    163     }
    164 
    165     return OK;
    166 }
    167 
    168 void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
    169     Mutex::Autolock autoLock(mLock);
    170 
    171     int64_t whenUs;
    172     if (delayUs > 0) {
    173         whenUs = GetNowUs() + delayUs;
    174     } else {
    175         whenUs = GetNowUs();
    176     }
    177 
    178     List<Event>::iterator it = mEventQueue.begin();
    179     while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
    180         ++it;
    181     }
    182 
    183     Event event;
    184     event.mWhenUs = whenUs;
    185     event.mMessage = msg;
    186 
    187     if (it == mEventQueue.begin()) {
    188         mQueueChangedCondition.signal();
    189     }
    190 
    191     mEventQueue.insert(it, event);
    192 }
    193 
    194 bool ALooper::loop() {
    195     Event event;
    196 
    197     {
    198         Mutex::Autolock autoLock(mLock);
    199         if (mThread == NULL && !mRunningLocally) {
    200             return false;
    201         }
    202         if (mEventQueue.empty()) {
    203             mQueueChangedCondition.wait(mLock);
    204             return true;
    205         }
    206         int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
    207         int64_t nowUs = GetNowUs();
    208 
    209         if (whenUs > nowUs) {
    210             int64_t delayUs = whenUs - nowUs;
    211             mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
    212 
    213             return true;
    214         }
    215 
    216         event = *mEventQueue.begin();
    217         mEventQueue.erase(mEventQueue.begin());
    218     }
    219 
    220     event.mMessage->deliver();
    221 
    222     // NOTE: It's important to note that at this point our "ALooper" object
    223     // may no longer exist (its final reference may have gone away while
    224     // delivering the message). We have made sure, however, that loop()
    225     // won't be called again.
    226 
    227     return true;
    228 }
    229 
    230 // to be called by AMessage::postAndAwaitResponse only
    231 sp<AReplyToken> ALooper::createReplyToken() {
    232     return new AReplyToken(this);
    233 }
    234 
    235 // to be called by AMessage::postAndAwaitResponse only
    236 status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
    237     // return status in case we want to handle an interrupted wait
    238     Mutex::Autolock autoLock(mRepliesLock);
    239     CHECK(replyToken != NULL);
    240     while (!replyToken->retrieveReply(response)) {
    241         {
    242             Mutex::Autolock autoLock(mLock);
    243             if (mThread == NULL) {
    244                 return -ENOENT;
    245             }
    246         }
    247         mRepliesCondition.wait(mRepliesLock);
    248     }
    249     return OK;
    250 }
    251 
    252 status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
    253     Mutex::Autolock autoLock(mRepliesLock);
    254     status_t err = replyToken->setReply(reply);
    255     if (err == OK) {
    256         mRepliesCondition.broadcast();
    257     }
    258     return err;
    259 }
    260 
    261 }  // namespace android
    262