Flutter Engine
message_loop_android.cc
Go to the documentation of this file.
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 
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 
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 
57 MessageLoopAndroid::~MessageLoopAndroid() {
58  int remove_result = ::ALooper_removeFd(looper_.get(), timer_fd_.get());
59  FML_CHECK(remove_result == 1);
60 }
61 
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 
80 void MessageLoopAndroid::Terminate() {
81  running_ = false;
82  ALooper_wake(looper_.get());
83 }
84 
85 void MessageLoopAndroid::WakeUp(fml::TimePoint time_point) {
86  bool result = TimerRearm(timer_fd_.get(), time_point);
87  FML_DCHECK(result);
88 }
89 
90 void MessageLoopAndroid::OnEventFired() {
91  if (TimerDrain(timer_fd_.get())) {
93  }
94 }
95 
96 } // namespace fml
#define FML_DCHECK(condition)
Definition: logging.h:86
const T & get() const
Definition: unique_object.h:87
Definition: ascii_trie.cc:9
int timerfd_create(int clockid, int flags)
Definition: timerfd.cc:17
static ALooper * AcquireLooperForThread()
static constexpr int kClockType
#define TFD_CLOEXEC
Definition: timerfd.h:32
#define FML_CHECK(condition)
Definition: logging.h:68
bool TimerDrain(int fd)
Definition: timerfd.cc:54
#define TFD_NONBLOCK
Definition: timerfd.h:33
bool TimerRearm(int fd, fml::TimePoint time_point)
Rearms the timer to expire at the given time point.
Definition: timerfd.cc:36