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