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
32namespace android {
33
34ALooperRoster gLooperRoster;
35
36struct 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
57protected:
58    virtual ~LooperThread() {}
59
60private:
61    ALooper *mLooper;
62    android_thread_id_t mThreadId;
63
64    DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
65};
66
67// static
68int64_t ALooper::GetNowUs() {
69    return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;
70}
71
72ALooper::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
79ALooper::~ALooper() {
80    stop();
81    // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along
82}
83
84void ALooper::setName(const char *name) {
85    mName = name;
86}
87
88ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
89    return gLooperRoster.registerHandler(this, handler);
90}
91
92void ALooper::unregisterHandler(handler_id handlerID) {
93    gLooperRoster.unregisterHandler(handlerID);
94}
95
96status_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
132status_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
168void 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
194bool 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
231sp<AReplyToken> ALooper::createReplyToken() {
232    return new AReplyToken(this);
233}
234
235// to be called by AMessage::postAndAwaitResponse only
236status_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
252status_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