blob: 61bac02ad368e9f4d6327f012ab1003516ae8321 [file] [log] [blame]
Andreas Huber72961232010-06-07 10:18:57 -07001/*
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"
Lajos Molnar3f274362015-03-05 14:35:41 -080019
20#include <media/stagefright/foundation/ADebug.h>
21
Andreas Huber72961232010-06-07 10:18:57 -070022#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
32namespace android {
33
34ALooperRoster gLooperRoster;
35
36struct ALooper::LooperThread : public Thread {
Andreas Huber42d7f832010-07-02 08:00:52 -070037 LooperThread(ALooper *looper, bool canCallJava)
38 : Thread(canCallJava),
Andreas Huberf8be8c02011-03-29 11:50:24 -070039 mLooper(looper),
40 mThreadId(NULL) {
41 }
42
43 virtual status_t readyToRun() {
44 mThreadId = androidGetThreadId();
45
46 return Thread::readyToRun();
Andreas Huber72961232010-06-07 10:18:57 -070047 }
48
49 virtual bool threadLoop() {
50 return mLooper->loop();
51 }
52
Andreas Huberf8be8c02011-03-29 11:50:24 -070053 bool isCurrentThread() const {
54 return mThreadId == androidGetThreadId();
55 }
56
Andreas Huber72961232010-06-07 10:18:57 -070057protected:
58 virtual ~LooperThread() {}
59
60private:
61 ALooper *mLooper;
Andreas Huberf8be8c02011-03-29 11:50:24 -070062 android_thread_id_t mThreadId;
Andreas Huber72961232010-06-07 10:18:57 -070063
64 DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
65};
66
67// static
68int64_t ALooper::GetNowUs() {
Chih-Hung Hsieh3794b242018-12-11 13:55:06 -080069 return systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
Andreas Huber72961232010-06-07 10:18:57 -070070}
71
Brian Lindahlb0174272023-01-17 09:45:36 -070072int64_t ALooper::getNowUs() {
73 return GetNowUs();
74}
75
Andreas Huber72961232010-06-07 10:18:57 -070076ALooper::ALooper()
77 : mRunningLocally(false) {
Marco Nelissen0b0f6072014-08-28 12:40:34 -070078 // clean up stale AHandlers. Doing it here instead of in the destructor avoids
79 // the side effect of objects being deleted from the unregister function recursively.
80 gLooperRoster.unregisterStaleHandlers();
Andreas Huber72961232010-06-07 10:18:57 -070081}
82
83ALooper::~ALooper() {
84 stop();
Marco Nelissen0b0f6072014-08-28 12:40:34 -070085 // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along
Andreas Huber72961232010-06-07 10:18:57 -070086}
87
Andreas Hubera814c1f2010-08-27 15:21:07 -070088void ALooper::setName(const char *name) {
89 mName = name;
90}
91
Andreas Huber72961232010-06-07 10:18:57 -070092ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
93 return gLooperRoster.registerHandler(this, handler);
94}
95
96void ALooper::unregisterHandler(handler_id handlerID) {
97 gLooperRoster.unregisterHandler(handlerID);
98}
99
Andreas Huber348a8ea2010-07-22 09:20:13 -0700100status_t ALooper::start(
101 bool runOnCallingThread, bool canCallJava, int32_t priority) {
Andreas Huber72961232010-06-07 10:18:57 -0700102 if (runOnCallingThread) {
103 {
104 Mutex::Autolock autoLock(mLock);
105
106 if (mThread != NULL || mRunningLocally) {
107 return INVALID_OPERATION;
108 }
109
110 mRunningLocally = true;
111 }
112
113 do {
114 } while (loop());
115
116 return OK;
117 }
118
119 Mutex::Autolock autoLock(mLock);
120
121 if (mThread != NULL || mRunningLocally) {
122 return INVALID_OPERATION;
123 }
124
Andreas Huber42d7f832010-07-02 08:00:52 -0700125 mThread = new LooperThread(this, canCallJava);
Andreas Huber72961232010-06-07 10:18:57 -0700126
Andreas Hubera814c1f2010-08-27 15:21:07 -0700127 status_t err = mThread->run(
128 mName.empty() ? "ALooper" : mName.c_str(), priority);
Andreas Huber72961232010-06-07 10:18:57 -0700129 if (err != OK) {
130 mThread.clear();
131 }
132
133 return err;
134}
135
136status_t ALooper::stop() {
137 sp<LooperThread> thread;
138 bool runningLocally;
139
140 {
141 Mutex::Autolock autoLock(mLock);
142
143 thread = mThread;
144 runningLocally = mRunningLocally;
145 mThread.clear();
146 mRunningLocally = false;
147 }
148
149 if (thread == NULL && !runningLocally) {
150 return INVALID_OPERATION;
151 }
152
153 if (thread != NULL) {
154 thread->requestExit();
155 }
156
157 mQueueChangedCondition.signal();
Ronghua Wu0abb2aa2015-10-21 13:42:59 -0700158 {
159 Mutex::Autolock autoLock(mRepliesLock);
160 mRepliesCondition.broadcast();
161 }
Andreas Huber72961232010-06-07 10:18:57 -0700162
Andreas Huberf8be8c02011-03-29 11:50:24 -0700163 if (!runningLocally && !thread->isCurrentThread()) {
164 // If not running locally and this thread _is_ the looper thread,
165 // the loop() function will return and never be called again.
Andreas Huber72961232010-06-07 10:18:57 -0700166 thread->requestExitAndWait();
167 }
168
169 return OK;
170}
171
172void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
173 Mutex::Autolock autoLock(mLock);
174
175 int64_t whenUs;
176 if (delayUs > 0) {
Brian Lindahlb0174272023-01-17 09:45:36 -0700177 int64_t nowUs = getNowUs();
Wei Jiab783f4b2018-10-25 11:16:44 -0700178 whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
179
Andreas Huber72961232010-06-07 10:18:57 -0700180 } else {
Brian Lindahlb0174272023-01-17 09:45:36 -0700181 whenUs = getNowUs();
Andreas Huber72961232010-06-07 10:18:57 -0700182 }
183
184 List<Event>::iterator it = mEventQueue.begin();
185 while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
186 ++it;
187 }
188
189 Event event;
190 event.mWhenUs = whenUs;
191 event.mMessage = msg;
Brian Lindahlb0174272023-01-17 09:45:36 -0700192 event.mToken = nullptr;
Andreas Huber72961232010-06-07 10:18:57 -0700193
194 if (it == mEventQueue.begin()) {
195 mQueueChangedCondition.signal();
196 }
197
198 mEventQueue.insert(it, event);
199}
200
Brian Lindahlb0174272023-01-17 09:45:36 -0700201status_t ALooper::postUnique(const sp<AMessage> &msg, const sp<RefBase> &token, int64_t delayUs) {
202 if (token == nullptr) {
203 return -EINVAL;
204 }
205 Mutex::Autolock autoLock(mLock);
206
207 int64_t whenUs;
208 if (delayUs > 0) {
209 int64_t nowUs = getNowUs();
210 whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);
211 } else {
212 whenUs = getNowUs();
213 }
214
215 // We only need to wake the loop up if we're rescheduling to the earliest event in the queue.
216 // This needs to be checked now, before we reschedule the message, in case this message is
217 // already at the beginning of the queue.
218 bool shouldAwakeLoop = mEventQueue.empty() || whenUs < mEventQueue.begin()->mWhenUs;
219
220 // Erase any previously-posted event with this token.
221 for (auto i = mEventQueue.begin(); i != mEventQueue.end();) {
222 if (i->mToken == token) {
223 i = mEventQueue.erase(i);
224 } else {
225 ++i;
226 }
227 }
228
229 // Find the insertion point for the rescheduled message.
230 List<Event>::iterator i = mEventQueue.begin();
231 while (i != mEventQueue.end() && i->mWhenUs <= whenUs) {
232 ++i;
233 }
234
235 Event event;
236 event.mWhenUs = whenUs;
237 event.mMessage = msg;
238 event.mToken = token;
239 mEventQueue.insert(i, event);
240
241 // If we rescheduled the event to be earlier than the first event, then we need to wake up the
242 // looper earlier than it was previously scheduled to be woken up. Otherwise, it can sleep until
243 // the previous wake-up time and then go to sleep again if needed.
244 if (shouldAwakeLoop){
245 mQueueChangedCondition.signal();
246 }
247 return OK;
248}
249
Andreas Huber72961232010-06-07 10:18:57 -0700250bool ALooper::loop() {
Brian Lindahlb0174272023-01-17 09:45:36 -0700251
Andreas Huber72961232010-06-07 10:18:57 -0700252 Event event;
253
254 {
255 Mutex::Autolock autoLock(mLock);
256 if (mThread == NULL && !mRunningLocally) {
257 return false;
258 }
259 if (mEventQueue.empty()) {
260 mQueueChangedCondition.wait(mLock);
261 return true;
262 }
263 int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
Brian Lindahlb0174272023-01-17 09:45:36 -0700264 int64_t nowUs = getNowUs();
Andreas Huber72961232010-06-07 10:18:57 -0700265
266 if (whenUs > nowUs) {
267 int64_t delayUs = whenUs - nowUs;
Wei Jiab783f4b2018-10-25 11:16:44 -0700268 if (delayUs > INT64_MAX / 1000) {
269 delayUs = INT64_MAX / 1000;
270 }
Andreas Huber72961232010-06-07 10:18:57 -0700271 mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
272
273 return true;
274 }
275
276 event = *mEventQueue.begin();
277 mEventQueue.erase(mEventQueue.begin());
278 }
279
Lajos Molnar5804a762015-03-04 17:00:10 -0800280 event.mMessage->deliver();
Andreas Huber72961232010-06-07 10:18:57 -0700281
Andreas Huberf8be8c02011-03-29 11:50:24 -0700282 // NOTE: It's important to note that at this point our "ALooper" object
283 // may no longer exist (its final reference may have gone away while
284 // delivering the message). We have made sure, however, that loop()
285 // won't be called again.
286
Andreas Huber72961232010-06-07 10:18:57 -0700287 return true;
288}
289
Lajos Molnar3f274362015-03-05 14:35:41 -0800290// to be called by AMessage::postAndAwaitResponse only
291sp<AReplyToken> ALooper::createReplyToken() {
292 return new AReplyToken(this);
293}
294
295// to be called by AMessage::postAndAwaitResponse only
296status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
297 // return status in case we want to handle an interrupted wait
298 Mutex::Autolock autoLock(mRepliesLock);
299 CHECK(replyToken != NULL);
Ronghua Wub49c3852015-10-26 10:17:37 -0700300 while (!replyToken->retrieveReply(response)) {
Ronghua Wu0abb2aa2015-10-21 13:42:59 -0700301 {
302 Mutex::Autolock autoLock(mLock);
303 if (mThread == NULL) {
Ronghua Wub49c3852015-10-26 10:17:37 -0700304 return -ENOENT;
Ronghua Wu0abb2aa2015-10-21 13:42:59 -0700305 }
306 }
Ronghua Wub49c3852015-10-26 10:17:37 -0700307 mRepliesCondition.wait(mRepliesLock);
Lajos Molnar3f274362015-03-05 14:35:41 -0800308 }
Ronghua Wub49c3852015-10-26 10:17:37 -0700309 return OK;
Lajos Molnar3f274362015-03-05 14:35:41 -0800310}
311
312status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
313 Mutex::Autolock autoLock(mRepliesLock);
314 status_t err = replyToken->setReply(reply);
315 if (err == OK) {
316 mRepliesCondition.broadcast();
317 }
318 return err;
319}
320
Andreas Huber72961232010-06-07 10:18:57 -0700321} // namespace android