• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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