1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/message_loop/message_pump_android.h"
6
7 // This file is included by modules that have host support but android/looper.h is not supported
8 // on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
9 #ifndef __BIONIC__
10 #define __REMOVED_IN(x) __attribute__((deprecated))
11 #endif
12 #include <android/looper.h>
13
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <jni.h>
17 #include <sys/eventfd.h>
18 #include <sys/timerfd.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <utility>
22
23 #include "base/android/jni_android.h"
24 #include "base/android/scoped_java_ref.h"
25 #include "base/check_op.h"
26 #include "base/notreached.h"
27 #include "base/numerics/safe_conversions.h"
28 #include "base/run_loop.h"
29 #include "build/build_config.h"
30
31 namespace base {
32
33 namespace {
34
35 // https://crbug.com/873588. The stack may not be aligned when the ALooper calls
36 // into our code due to the inconsistent ABI on older Android OS versions.
37 #if defined(ARCH_CPU_X86)
38 #define STACK_ALIGN __attribute__((force_align_arg_pointer))
39 #else
40 #define STACK_ALIGN
41 #endif
42
NonDelayedLooperCallback(int fd,int events,void * data)43 STACK_ALIGN int NonDelayedLooperCallback(int fd, int events, void* data) {
44 if (events & ALOOPER_EVENT_HANGUP)
45 return 0;
46
47 DCHECK(events & ALOOPER_EVENT_INPUT);
48 MessagePumpForUI* pump = reinterpret_cast<MessagePumpForUI*>(data);
49 pump->OnNonDelayedLooperCallback();
50 return 1; // continue listening for events
51 }
52
DelayedLooperCallback(int fd,int events,void * data)53 STACK_ALIGN int DelayedLooperCallback(int fd, int events, void* data) {
54 if (events & ALOOPER_EVENT_HANGUP)
55 return 0;
56
57 DCHECK(events & ALOOPER_EVENT_INPUT);
58 MessagePumpForUI* pump = reinterpret_cast<MessagePumpForUI*>(data);
59 pump->OnDelayedLooperCallback();
60 return 1; // continue listening for events
61 }
62
63 // A bit added to the |non_delayed_fd_| to keep it signaled when we yield to
64 // native work below.
65 constexpr uint64_t kTryNativeWorkBeforeIdleBit = uint64_t(1) << 32;
66 } // namespace
67
MessagePumpForUI()68 MessagePumpForUI::MessagePumpForUI()
69 : env_(base::android::AttachCurrentThread()) {
70 // The Android native ALooper uses epoll to poll our file descriptors and wake
71 // us up. We use a simple level-triggered eventfd to signal that non-delayed
72 // work is available, and a timerfd to signal when delayed work is ready to
73 // be run.
74 non_delayed_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
75 CHECK_NE(non_delayed_fd_, -1);
76 DCHECK_EQ(TimeTicks::GetClock(), TimeTicks::Clock::LINUX_CLOCK_MONOTONIC);
77
78 delayed_fd_ = checked_cast<int>(
79 timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC));
80 CHECK_NE(delayed_fd_, -1);
81
82 looper_ = ALooper_prepare(0);
83 DCHECK(looper_);
84 // Add a reference to the looper so it isn't deleted on us.
85 ALooper_acquire(looper_);
86 ALooper_addFd(looper_, non_delayed_fd_, 0, ALOOPER_EVENT_INPUT,
87 &NonDelayedLooperCallback, reinterpret_cast<void*>(this));
88 ALooper_addFd(looper_, delayed_fd_, 0, ALOOPER_EVENT_INPUT,
89 &DelayedLooperCallback, reinterpret_cast<void*>(this));
90 }
91
~MessagePumpForUI()92 MessagePumpForUI::~MessagePumpForUI() {
93 DCHECK_EQ(ALooper_forThread(), looper_);
94 ALooper_removeFd(looper_, non_delayed_fd_);
95 ALooper_removeFd(looper_, delayed_fd_);
96 ALooper_release(looper_);
97 looper_ = nullptr;
98
99 close(non_delayed_fd_);
100 close(delayed_fd_);
101 }
102
OnDelayedLooperCallback()103 void MessagePumpForUI::OnDelayedLooperCallback() {
104 // There may be non-Chromium callbacks on the same ALooper which may have left
105 // a pending exception set, and ALooper does not check for this between
106 // callbacks. Check here, and if there's already an exception, just skip this
107 // iteration without clearing the fd. If the exception ends up being non-fatal
108 // then we'll just get called again on the next polling iteration.
109 if (base::android::HasException(env_))
110 return;
111
112 // ALooper_pollOnce may call this after Quit() if OnNonDelayedLooperCallback()
113 // resulted in Quit() in the same round.
114 if (ShouldQuit())
115 return;
116
117 // Clear the fd.
118 uint64_t value;
119 long ret = read(delayed_fd_, &value, sizeof(value));
120
121 // TODO(mthiesse): Figure out how it's possible to hit EAGAIN here.
122 // According to http://man7.org/linux/man-pages/man2/timerfd_create.2.html
123 // EAGAIN only happens if no timer has expired. Also according to the man page
124 // poll only returns readable when a timer has expired. So this function will
125 // only be called when a timer has expired, but reading reveals no timer has
126 // expired...
127 // Quit() and ScheduleDelayedWork() are the only other functions that touch
128 // the timerfd, and they both run on the same thread as this callback, so
129 // there are no obvious timing or multi-threading related issues.
130 DPCHECK(ret >= 0 || errno == EAGAIN);
131 DoDelayedLooperWork();
132 }
133
DoDelayedLooperWork()134 void MessagePumpForUI::DoDelayedLooperWork() {
135 delayed_scheduled_time_.reset();
136
137 Delegate::NextWorkInfo next_work_info = delegate_->DoWork();
138
139 if (ShouldQuit())
140 return;
141
142 if (next_work_info.is_immediate()) {
143 ScheduleWork();
144 return;
145 }
146
147 DoIdleWork();
148 if (!next_work_info.delayed_run_time.is_max())
149 ScheduleDelayedWork(next_work_info);
150 }
151
OnNonDelayedLooperCallback()152 void MessagePumpForUI::OnNonDelayedLooperCallback() {
153 // There may be non-Chromium callbacks on the same ALooper which may have left
154 // a pending exception set, and ALooper does not check for this between
155 // callbacks. Check here, and if there's already an exception, just skip this
156 // iteration without clearing the fd. If the exception ends up being non-fatal
157 // then we'll just get called again on the next polling iteration.
158 if (base::android::HasException(env_))
159 return;
160
161 // ALooper_pollOnce may call this after Quit() if OnDelayedLooperCallback()
162 // resulted in Quit() in the same round.
163 if (ShouldQuit())
164 return;
165
166 // We're about to process all the work requested by ScheduleWork().
167 // MessagePump users are expected to do their best not to invoke
168 // ScheduleWork() again before DoWork() returns a non-immediate
169 // NextWorkInfo below. Hence, capturing the file descriptor's value now and
170 // resetting its contents to 0 should be okay. The value currently stored
171 // should be greater than 0 since work having been scheduled is the reason
172 // we're here. See http://man7.org/linux/man-pages/man2/eventfd.2.html
173 uint64_t value = 0;
174 long ret = read(non_delayed_fd_, &value, sizeof(value));
175 DPCHECK(ret >= 0);
176 DCHECK_GT(value, 0U);
177 bool do_idle_work = value == kTryNativeWorkBeforeIdleBit;
178 DoNonDelayedLooperWork(do_idle_work);
179 }
180
DoNonDelayedLooperWork(bool do_idle_work)181 void MessagePumpForUI::DoNonDelayedLooperWork(bool do_idle_work) {
182 // Note: We can't skip DoWork() even if |do_idle_work| is true here (i.e. no
183 // additional ScheduleWork() since yielding to native) as delayed tasks might
184 // have come in and we need to re-sample |next_work_info|.
185
186 // Runs all application tasks scheduled to run.
187 Delegate::NextWorkInfo next_work_info;
188 do {
189 if (ShouldQuit())
190 return;
191
192 next_work_info = delegate_->DoWork();
193 // If we are prioritizing native, and the next work would normally run
194 // immediately, skip the next work and let the native work items have a
195 // chance to run. This is useful when user input is waiting for native to
196 // have a chance to run.
197 if (next_work_info.is_immediate() && next_work_info.yield_to_native) {
198 ScheduleWork();
199 return;
200 }
201 } while (next_work_info.is_immediate());
202
203 // Do not resignal |non_delayed_fd_| if we're quitting (this pump doesn't
204 // allow nesting so needing to resume in an outer loop is not an issue
205 // either).
206 if (ShouldQuit())
207 return;
208
209 // Before declaring this loop idle, yield to native work items and arrange to
210 // be called again (unless we're already in that second call).
211 if (!do_idle_work) {
212 ScheduleWorkInternal(/*do_idle_work=*/true);
213 return;
214 }
215
216 // We yielded to native work items already and they didn't generate a
217 // ScheduleWork() request so we can declare idleness. It's possible for a
218 // ScheduleWork() request to come in racily while this method unwinds, this is
219 // fine and will merely result in it being re-invoked shortly after it
220 // returns.
221 // TODO(scheduler-dev): this doesn't account for tasks that don't ever call
222 // SchedulerWork() but still keep the system non-idle (e.g., the Java Handler
223 // API). It would be better to add an API to query the presence of native
224 // tasks instead of relying on yielding once + kTryNativeWorkBeforeIdleBit.
225 DCHECK(do_idle_work);
226
227 if (ShouldQuit())
228 return;
229
230 // At this point, the java looper might not be idle - it's impossible to know
231 // pre-Android-M, so we may end up doing Idle work while java tasks are still
232 // queued up. Note that this won't cause us to fail to run java tasks using
233 // QuitWhenIdle, as the JavaHandlerThread will finish running all currently
234 // scheduled tasks before it quits. Also note that we can't just add an idle
235 // callback to the java looper, as that will fire even if application tasks
236 // are still queued up.
237 DoIdleWork();
238 if (!next_work_info.delayed_run_time.is_max()) {
239 ScheduleDelayedWork(next_work_info);
240 }
241 }
242
DoIdleWork()243 void MessagePumpForUI::DoIdleWork() {
244 if (delegate_->DoIdleWork()) {
245 // If DoIdleWork() resulted in any work, we're not idle yet. We need to pump
246 // the loop here because we may in fact be idle after doing idle work
247 // without any new tasks being queued.
248 ScheduleWork();
249 }
250 }
251
Run(Delegate * delegate)252 void MessagePumpForUI::Run(Delegate* delegate) {
253 CHECK(false) << "Unexpected call to Run()";
254 }
255
Attach(Delegate * delegate)256 void MessagePumpForUI::Attach(Delegate* delegate) {
257 DCHECK(!quit_);
258
259 // Since the Looper is controlled by the UI thread or JavaHandlerThread, we
260 // can't use Run() like we do on other platforms or we would prevent Java
261 // tasks from running. Instead we create and initialize a run loop here, then
262 // return control back to the Looper.
263
264 SetDelegate(delegate);
265 run_loop_ = std::make_unique<RunLoop>();
266 // Since the RunLoop was just created above, BeforeRun should be guaranteed to
267 // return true (it only returns false if the RunLoop has been Quit already).
268 if (!run_loop_->BeforeRun())
269 NOTREACHED();
270 }
271
Quit()272 void MessagePumpForUI::Quit() {
273 if (quit_)
274 return;
275
276 quit_ = true;
277
278 int64_t value;
279 // Clear any pending timer.
280 read(delayed_fd_, &value, sizeof(value));
281 // Clear the eventfd.
282 read(non_delayed_fd_, &value, sizeof(value));
283
284 if (run_loop_) {
285 run_loop_->AfterRun();
286 run_loop_ = nullptr;
287 }
288 if (on_quit_callback_) {
289 std::move(on_quit_callback_).Run();
290 }
291 }
292
ScheduleWork()293 void MessagePumpForUI::ScheduleWork() {
294 ScheduleWorkInternal(/*do_idle_work=*/false);
295 }
296
ScheduleWorkInternal(bool do_idle_work)297 void MessagePumpForUI::ScheduleWorkInternal(bool do_idle_work) {
298 // Write (add) |value| to the eventfd. This tells the Looper to wake up and
299 // call our callback, allowing us to run tasks. This also allows us to detect,
300 // when we clear the fd, whether additional work was scheduled after we
301 // finished performing work, but before we cleared the fd, as we'll read back
302 // >=2 instead of 1 in that case. See the eventfd man pages
303 // (http://man7.org/linux/man-pages/man2/eventfd.2.html) for details on how
304 // the read and write APIs for this file descriptor work, specifically without
305 // EFD_SEMAPHORE.
306 // Note: Calls with |do_idle_work| set to true may race with potential calls
307 // where the parameter is false. This is fine as write() is adding |value|,
308 // not overwriting the existing value, and as such racing calls would merely
309 // have their values added together. Since idle work is only executed when the
310 // value read equals kTryNativeWorkBeforeIdleBit, a race would prevent idle
311 // work from being run and trigger another call to this method with
312 // |do_idle_work| set to true.
313 uint64_t value = do_idle_work ? kTryNativeWorkBeforeIdleBit : 1;
314 long ret = write(non_delayed_fd_, &value, sizeof(value));
315 DPCHECK(ret >= 0);
316 }
317
ScheduleDelayedWork(const Delegate::NextWorkInfo & next_work_info)318 void MessagePumpForUI::ScheduleDelayedWork(
319 const Delegate::NextWorkInfo& next_work_info) {
320 if (ShouldQuit())
321 return;
322
323 if (delayed_scheduled_time_ &&
324 *delayed_scheduled_time_ == next_work_info.delayed_run_time) {
325 return;
326 }
327
328 DCHECK(!next_work_info.is_immediate());
329 delayed_scheduled_time_ = next_work_info.delayed_run_time;
330 int64_t nanos =
331 next_work_info.delayed_run_time.since_origin().InNanoseconds();
332 struct itimerspec ts;
333 ts.it_interval.tv_sec = 0; // Don't repeat.
334 ts.it_interval.tv_nsec = 0;
335 ts.it_value.tv_sec =
336 static_cast<time_t>(nanos / TimeTicks::kNanosecondsPerSecond);
337 ts.it_value.tv_nsec = nanos % TimeTicks::kNanosecondsPerSecond;
338
339 long ret = timerfd_settime(delayed_fd_, TFD_TIMER_ABSTIME, &ts, nullptr);
340 DPCHECK(ret >= 0);
341 }
342
QuitWhenIdle(base::OnceClosure callback)343 void MessagePumpForUI::QuitWhenIdle(base::OnceClosure callback) {
344 DCHECK(!on_quit_callback_);
345 DCHECK(run_loop_);
346 on_quit_callback_ = std::move(callback);
347 run_loop_->QuitWhenIdle();
348 // Pump the loop in case we're already idle.
349 ScheduleWork();
350 }
351
SetDelegate(Delegate * delegate)352 MessagePump::Delegate* MessagePumpForUI::SetDelegate(Delegate* delegate) {
353 return std::exchange(delegate_, delegate);
354 }
355
SetQuit(bool quit)356 bool MessagePumpForUI::SetQuit(bool quit) {
357 return std::exchange(quit_, quit);
358 }
359
360 } // namespace base
361