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 {
LooperThreadandroid::ALooper::LooperThread34     LooperThread(ALooper *looper, bool canCallJava)
35         : Thread(canCallJava),
36           mLooper(looper),
37           mThreadId(NULL) {
38     }
39 
readyToRunandroid::ALooper::LooperThread40     virtual status_t readyToRun() {
41         mThreadId = androidGetThreadId();
42 
43         return Thread::readyToRun();
44     }
45 
threadLoopandroid::ALooper::LooperThread46     virtual bool threadLoop() {
47         return mLooper->loop();
48     }
49 
isCurrentThreadandroid::ALooper::LooperThread50     bool isCurrentThread() const {
51         return mThreadId == androidGetThreadId();
52     }
53 
54 protected:
~LooperThreadandroid::ALooper::LooperThread55     virtual ~LooperThread() {}
56 
57 private:
58     ALooper *mLooper;
59     android_thread_id_t mThreadId;
60 
61     DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
62 };
63 
64 // static
GetNowUs()65 int64_t ALooper::GetNowUs() {
66     return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;
67 }
68 
ALooper()69 ALooper::ALooper()
70     : mRunningLocally(false) {
71     // clean up stale AHandlers. Doing it here instead of in the destructor avoids
72     // the side effect of objects being deleted from the unregister function recursively.
73     gLooperRoster.unregisterStaleHandlers();
74 }
75 
~ALooper()76 ALooper::~ALooper() {
77     stop();
78     // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along
79 }
80 
setName(const char * name)81 void ALooper::setName(const char *name) {
82     mName = name;
83 }
84 
registerHandler(const sp<AHandler> & handler)85 ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
86     return gLooperRoster.registerHandler(this, handler);
87 }
88 
unregisterHandler(handler_id handlerID)89 void ALooper::unregisterHandler(handler_id handlerID) {
90     gLooperRoster.unregisterHandler(handlerID);
91 }
92 
start(bool runOnCallingThread,bool canCallJava,int32_t priority)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 
stop()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 
post(const sp<AMessage> & msg,int64_t delayUs)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 
loop()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