ALooper.cpp revision a814c1fdc2acf0ed2ee3b175110f6039be7c4873
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