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     }
     38 
     39     virtual bool threadLoop() {
     40         return mLooper->loop();
     41     }
     42 
     43 protected:
     44     virtual ~LooperThread() {}
     45 
     46 private:
     47     ALooper *mLooper;
     48 
     49     DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
     50 };
     51 
     52 // static
     53 int64_t ALooper::GetNowUs() {
     54     struct timeval tv;
     55     gettimeofday(&tv, NULL);
     56 
     57     return (int64_t)tv.tv_sec * 1000000ll + tv.tv_usec;
     58 }
     59 
     60 ALooper::ALooper()
     61     : mRunningLocally(false) {
     62 }
     63 
     64 ALooper::~ALooper() {
     65     stop();
     66 }
     67 
     68 void ALooper::setName(const char *name) {
     69     mName = name;
     70 }
     71 
     72 ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
     73     return gLooperRoster.registerHandler(this, handler);
     74 }
     75 
     76 void ALooper::unregisterHandler(handler_id handlerID) {
     77     gLooperRoster.unregisterHandler(handlerID);
     78 }
     79 
     80 status_t ALooper::start(
     81         bool runOnCallingThread, bool canCallJava, int32_t priority) {
     82     if (runOnCallingThread) {
     83         {
     84             Mutex::Autolock autoLock(mLock);
     85 
     86             if (mThread != NULL || mRunningLocally) {
     87                 return INVALID_OPERATION;
     88             }
     89 
     90             mRunningLocally = true;
     91         }
     92 
     93         do {
     94         } while (loop());
     95 
     96         return OK;
     97     }
     98 
     99     Mutex::Autolock autoLock(mLock);
    100 
    101     if (mThread != NULL || mRunningLocally) {
    102         return INVALID_OPERATION;
    103     }
    104 
    105     mThread = new LooperThread(this, canCallJava);
    106 
    107     status_t err = mThread->run(
    108             mName.empty() ? "ALooper" : mName.c_str(), priority);
    109     if (err != OK) {
    110         mThread.clear();
    111     }
    112 
    113     return err;
    114 }
    115 
    116 status_t ALooper::stop() {
    117     sp<LooperThread> thread;
    118     bool runningLocally;
    119 
    120     {
    121         Mutex::Autolock autoLock(mLock);
    122 
    123         thread = mThread;
    124         runningLocally = mRunningLocally;
    125         mThread.clear();
    126         mRunningLocally = false;
    127     }
    128 
    129     if (thread == NULL && !runningLocally) {
    130         return INVALID_OPERATION;
    131     }
    132 
    133     if (thread != NULL) {
    134         thread->requestExit();
    135     }
    136 
    137     mQueueChangedCondition.signal();
    138 
    139     if (!runningLocally) {
    140         thread->requestExitAndWait();
    141     }
    142 
    143     return OK;
    144 }
    145 
    146 void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
    147     Mutex::Autolock autoLock(mLock);
    148 
    149     int64_t whenUs;
    150     if (delayUs > 0) {
    151         whenUs = GetNowUs() + delayUs;
    152     } else {
    153         whenUs = GetNowUs();
    154     }
    155 
    156     List<Event>::iterator it = mEventQueue.begin();
    157     while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
    158         ++it;
    159     }
    160 
    161     Event event;
    162     event.mWhenUs = whenUs;
    163     event.mMessage = msg;
    164 
    165     if (it == mEventQueue.begin()) {
    166         mQueueChangedCondition.signal();
    167     }
    168 
    169     mEventQueue.insert(it, event);
    170 }
    171 
    172 bool ALooper::loop() {
    173     Event event;
    174 
    175     {
    176         Mutex::Autolock autoLock(mLock);
    177         if (mThread == NULL && !mRunningLocally) {
    178             return false;
    179         }
    180         if (mEventQueue.empty()) {
    181             mQueueChangedCondition.wait(mLock);
    182             return true;
    183         }
    184         int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
    185         int64_t nowUs = GetNowUs();
    186 
    187         if (whenUs > nowUs) {
    188             int64_t delayUs = whenUs - nowUs;
    189             mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
    190 
    191             return true;
    192         }
    193 
    194         event = *mEventQueue.begin();
    195         mEventQueue.erase(mEventQueue.begin());
    196     }
    197 
    198     gLooperRoster.deliverMessage(event.mMessage);
    199 
    200     return true;
    201 }
    202 
    203 }  // namespace android
    204