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