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 } 72 73 ALooper::~ALooper() { 74 stop(); 75 76 // Since this looper is "dead" (or as good as dead by now), 77 // have ALooperRoster unregister any handlers still registered for it. 78 gLooperRoster.unregisterStaleHandlers(); 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