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 int64_t nowUs = GetNowUs(); 174 whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs); 175 176 } else { 177 whenUs = GetNowUs(); 178 } 179 180 List<Event>::iterator it = mEventQueue.begin(); 181 while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) { 182 ++it; 183 } 184 185 Event event; 186 event.mWhenUs = whenUs; 187 event.mMessage = msg; 188 189 if (it == mEventQueue.begin()) { 190 mQueueChangedCondition.signal(); 191 } 192 193 mEventQueue.insert(it, event); 194 } 195 196 bool ALooper::loop() { 197 Event event; 198 199 { 200 Mutex::Autolock autoLock(mLock); 201 if (mThread == NULL && !mRunningLocally) { 202 return false; 203 } 204 if (mEventQueue.empty()) { 205 mQueueChangedCondition.wait(mLock); 206 return true; 207 } 208 int64_t whenUs = (*mEventQueue.begin()).mWhenUs; 209 int64_t nowUs = GetNowUs(); 210 211 if (whenUs > nowUs) { 212 int64_t delayUs = whenUs - nowUs; 213 if (delayUs > INT64_MAX / 1000) { 214 delayUs = INT64_MAX / 1000; 215 } 216 mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll); 217 218 return true; 219 } 220 221 event = *mEventQueue.begin(); 222 mEventQueue.erase(mEventQueue.begin()); 223 } 224 225 event.mMessage->deliver(); 226 227 // NOTE: It's important to note that at this point our "ALooper" object 228 // may no longer exist (its final reference may have gone away while 229 // delivering the message). We have made sure, however, that loop() 230 // won't be called again. 231 232 return true; 233 } 234 235 // to be called by AMessage::postAndAwaitResponse only 236 sp<AReplyToken> ALooper::createReplyToken() { 237 return new AReplyToken(this); 238 } 239 240 // to be called by AMessage::postAndAwaitResponse only 241 status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) { 242 // return status in case we want to handle an interrupted wait 243 Mutex::Autolock autoLock(mRepliesLock); 244 CHECK(replyToken != NULL); 245 while (!replyToken->retrieveReply(response)) { 246 { 247 Mutex::Autolock autoLock(mLock); 248 if (mThread == NULL) { 249 return -ENOENT; 250 } 251 } 252 mRepliesCondition.wait(mRepliesLock); 253 } 254 return OK; 255 } 256 257 status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) { 258 Mutex::Autolock autoLock(mRepliesLock); 259 status_t err = replyToken->setReply(reply); 260 if (err == OK) { 261 mRepliesCondition.broadcast(); 262 } 263 return err; 264 } 265 266 } // namespace android 267