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 | |
28 | namespace fml { |
29 | |
30 | fml::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 | |
46 | MessageLoopImpl::MessageLoopImpl() |
47 | : task_queue_(MessageLoopTaskQueues::GetInstance()), |
48 | queue_id_(task_queue_->CreateTaskQueue()), |
49 | terminated_(false) { |
50 | task_queue_->SetWakeable(queue_id_, this); |
51 | } |
52 | |
53 | MessageLoopImpl::~MessageLoopImpl() { |
54 | task_queue_->Dispose(queue_id_); |
55 | } |
56 | |
57 | void 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 | |
69 | void 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 | |
82 | void 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 | |
89 | void 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 | |
115 | void MessageLoopImpl::DoTerminate() { |
116 | terminated_ = true; |
117 | Terminate(); |
118 | } |
119 | |
120 | void 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 | |
136 | void MessageLoopImpl::RunExpiredTasksNow() { |
137 | FlushTasks(FlushType::kAll); |
138 | } |
139 | |
140 | void MessageLoopImpl::RunSingleExpiredTaskNow() { |
141 | FlushTasks(FlushType::kSingle); |
142 | } |
143 | |
144 | TaskQueueId MessageLoopImpl::GetTaskQueueId() const { |
145 | return queue_id_; |
146 | } |
147 | |
148 | } // namespace fml |
149 | |