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#define FML_USED_ON_EMBEDDER
6
7#include "flutter/fml/message_loop_impl.h"
8
9#include <algorithm>
10#include <vector>
11
12#include "flutter/fml/build_config.h"
13#include "flutter/fml/logging.h"
14#include "flutter/fml/trace_event.h"
15
16#if OS_MACOSX
17#include "flutter/fml/platform/darwin/message_loop_darwin.h"
18#elif OS_ANDROID
19#include "flutter/fml/platform/android/message_loop_android.h"
20#elif OS_FUCHSIA
21#include "flutter/fml/platform/fuchsia/message_loop_fuchsia.h"
22#elif OS_LINUX
23#include "flutter/fml/platform/linux/message_loop_linux.h"
24#elif OS_WIN
25#include "flutter/fml/platform/win/message_loop_win.h"
26#endif
27
28namespace fml {
29
30fml::RefPtr<MessageLoopImpl> MessageLoopImpl::Create() {
31#if OS_MACOSX
32 return fml::MakeRefCounted<MessageLoopDarwin>();
33#elif OS_ANDROID
34 return fml::MakeRefCounted<MessageLoopAndroid>();
35#elif OS_FUCHSIA
36 return fml::MakeRefCounted<MessageLoopFuchsia>();
37#elif OS_LINUX
38 return fml::MakeRefCounted<MessageLoopLinux>();
39#elif OS_WIN
40 return fml::MakeRefCounted<MessageLoopWin>();
41#else
42 return nullptr;
43#endif
44}
45
46MessageLoopImpl::MessageLoopImpl()
47 : task_queue_(MessageLoopTaskQueues::GetInstance()),
48 queue_id_(task_queue_->CreateTaskQueue()),
49 terminated_(false) {
50 task_queue_->SetWakeable(queue_id_, this);
51}
52
53MessageLoopImpl::~MessageLoopImpl() {
54 task_queue_->Dispose(queue_id_);
55}
56
57void MessageLoopImpl::PostTask(const fml::closure& task,
58 fml::TimePoint target_time) {
59 FML_DCHECK(task != nullptr);
60 FML_DCHECK(task != nullptr);
61 if (terminated_) {
62 // If the message loop has already been terminated, PostTask should destruct
63 // |task| synchronously within this function.
64 return;
65 }
66 task_queue_->RegisterTask(queue_id_, task, target_time);
67}
68
69void MessageLoopImpl::AddTaskObserver(intptr_t key,
70 const fml::closure& callback) {
71 FML_DCHECK(callback != nullptr);
72 FML_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this)
73 << "Message loop task observer must be added on the same thread as the "
74 "loop.";
75 if (callback != nullptr) {
76 task_queue_->AddTaskObserver(queue_id_, key, callback);
77 } else {
78 FML_LOG(ERROR) << "Tried to add a null TaskObserver.";
79 }
80}
81
82void MessageLoopImpl::RemoveTaskObserver(intptr_t key) {
83 FML_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this)
84 << "Message loop task observer must be removed from the same thread as "
85 "the loop.";
86 task_queue_->RemoveTaskObserver(queue_id_, key);
87}
88
89void MessageLoopImpl::DoRun() {
90 if (terminated_) {
91 // Message loops may be run only once.
92 return;
93 }
94
95 // Allow the implementation to do its thing.
96 Run();
97
98 // The loop may have been implicitly terminated. This can happen if the
99 // implementation supports termination via platform specific APIs or just
100 // error conditions. Set the terminated flag manually.
101 terminated_ = true;
102
103 // The message loop is shutting down. Check if there are expired tasks. This
104 // is the last chance for expired tasks to be serviced. Make sure the
105 // terminated flag is already set so we don't accrue additional tasks now.
106 RunExpiredTasksNow();
107
108 // When the message loop is in the process of shutting down, pending tasks
109 // should be destructed on the message loop's thread. We have just returned
110 // from the implementations |Run| method which we know is on the correct
111 // thread. Drop all pending tasks on the floor.
112 task_queue_->DisposeTasks(queue_id_);
113}
114
115void MessageLoopImpl::DoTerminate() {
116 terminated_ = true;
117 Terminate();
118}
119
120void MessageLoopImpl::FlushTasks(FlushType type) {
121 TRACE_EVENT0("fml", "MessageLoop::FlushTasks");
122 std::vector<fml::closure> invocations;
123
124 task_queue_->GetTasksToRunNow(queue_id_, type, invocations);
125
126 for (const auto& invocation : invocations) {
127 invocation();
128 std::vector<fml::closure> observers =
129 task_queue_->GetObserversToNotify(queue_id_);
130 for (const auto& observer : observers) {
131 observer();
132 }
133 }
134}
135
136void MessageLoopImpl::RunExpiredTasksNow() {
137 FlushTasks(FlushType::kAll);
138}
139
140void MessageLoopImpl::RunSingleExpiredTaskNow() {
141 FlushTasks(FlushType::kSingle);
142}
143
144TaskQueueId MessageLoopImpl::GetTaskQueueId() const {
145 return queue_id_;
146}
147
148} // namespace fml
149