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 } 38 39 virtual bool threadLoop() { 40 return mLooper->loop(); 41 } 42 43protected: 44 virtual ~LooperThread() {} 45 46private: 47 ALooper *mLooper; 48 49 DISALLOW_EVIL_CONSTRUCTORS(LooperThread); 50}; 51 52// static 53int64_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 60ALooper::ALooper() 61 : mRunningLocally(false) { 62} 63 64ALooper::~ALooper() { 65 stop(); 66} 67 68void ALooper::setName(const char *name) { 69 mName = name; 70} 71 72ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) { 73 return gLooperRoster.registerHandler(this, handler); 74} 75 76void ALooper::unregisterHandler(handler_id handlerID) { 77 gLooperRoster.unregisterHandler(handlerID); 78} 79 80status_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 116status_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 146void 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 172bool 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