1 // Copyright 2013 The Flutter Authors. All rights reserved.
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 "flutter/fml/platform/android/message_loop_android.h"
6
7 #include <fcntl.h>
8 #include <unistd.h>
9
10 #include "flutter/fml/platform/linux/timerfd.h"
11
12 namespace fml {
13
14 static constexpr int kClockType = CLOCK_MONOTONIC;
15
AcquireLooperForThread()16 static ALooper* AcquireLooperForThread() {
17 ALooper* looper = ALooper_forThread();
18
19 if (looper == nullptr) {
20 // No looper has been configured for the current thread. Create one and
21 // return the same.
22 looper = ALooper_prepare(0);
23 }
24
25 // The thread already has a looper. Acquire a reference to the same and return
26 // it.
27 ALooper_acquire(looper);
28 return looper;
29 }
30
MessageLoopAndroid()31 MessageLoopAndroid::MessageLoopAndroid()
32 : looper_(AcquireLooperForThread()),
33 timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)),
34 running_(false) {
35 FML_CHECK(looper_.is_valid());
36 FML_CHECK(timer_fd_.is_valid());
37
38 static const int kWakeEvents = ALOOPER_EVENT_INPUT;
39
40 ALooper_callbackFunc read_event_fd = [](int, int events, void* data) -> int {
41 if (events & kWakeEvents) {
42 reinterpret_cast<MessageLoopAndroid*>(data)->OnEventFired();
43 }
44 return 1; // continue receiving callbacks
45 };
46
47 int add_result = ::ALooper_addFd(looper_.get(), // looper
48 timer_fd_.get(), // fd
49 ALOOPER_POLL_CALLBACK, // ident
50 kWakeEvents, // events
51 read_event_fd, // callback
52 this // baton
53 );
54 FML_CHECK(add_result == 1);
55 }
56
~MessageLoopAndroid()57 MessageLoopAndroid::~MessageLoopAndroid() {
58 int remove_result = ::ALooper_removeFd(looper_.get(), timer_fd_.get());
59 FML_CHECK(remove_result == 1);
60 }
61
Run()62 void MessageLoopAndroid::Run() {
63 FML_DCHECK(looper_.get() == ALooper_forThread());
64
65 running_ = true;
66
67 while (running_) {
68 int result = ::ALooper_pollOnce(-1, // infinite timeout
69 nullptr, // out fd,
70 nullptr, // out events,
71 nullptr // out data
72 );
73 if (result == ALOOPER_POLL_TIMEOUT || result == ALOOPER_POLL_ERROR) {
74 // This handles the case where the loop is terminated using ALooper APIs.
75 running_ = false;
76 }
77 }
78 }
79
Terminate()80 void MessageLoopAndroid::Terminate() {
81 running_ = false;
82 ALooper_wake(looper_.get());
83 }
84
WakeUp(fml::TimePoint time_point)85 void MessageLoopAndroid::WakeUp(fml::TimePoint time_point) {
86 bool result = TimerRearm(timer_fd_.get(), time_point);
87 FML_DCHECK(result);
88 }
89
OnEventFired()90 void MessageLoopAndroid::OnEventFired() {
91 if (TimerDrain(timer_fd_.get())) {
92 RunExpiredTasksNow();
93 }
94 }
95
96 } // namespace fml
97