ALooper.cpp revision 0b0f6075377260e006e860e3ba296f5504a6c891
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          mThreadId(NULL) {
38    }
39
40    virtual status_t readyToRun() {
41        mThreadId = androidGetThreadId();
42
43        return Thread::readyToRun();
44    }
45
46    virtual bool threadLoop() {
47        return mLooper->loop();
48    }
49
50    bool isCurrentThread() const {
51        return mThreadId == androidGetThreadId();
52    }
53
54protected:
55    virtual ~LooperThread() {}
56
57private:
58    ALooper *mLooper;
59    android_thread_id_t mThreadId;
60
61    DISALLOW_EVIL_CONSTRUCTORS(LooperThread);
62};
63
64// static
65int64_t ALooper::GetNowUs() {
66    return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;
67}
68
69ALooper::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
76ALooper::~ALooper() {
77    stop();
78    // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along
79}
80
81void ALooper::setName(const char *name) {
82    mName = name;
83}
84
85ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
86    return gLooperRoster.registerHandler(this, handler);
87}
88
89void ALooper::unregisterHandler(handler_id handlerID) {
90    gLooperRoster.unregisterHandler(handlerID);
91}
92
93status_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
129status_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
161void 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
187bool 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