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