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 // This is why we can't yet export the UI thread to embedders.
6 #define FML_USED_ON_EMBEDDER
7
8 #include "flutter/shell/platform/embedder/embedder_thread_host.h"
9
10 #include "flutter/fml/message_loop.h"
11 #include "flutter/shell/platform/embedder/embedder_safe_access.h"
12
13 namespace flutter {
14
CreateEmbedderTaskRunner(const FlutterTaskRunnerDescription * description)15 static fml::RefPtr<EmbedderTaskRunner> CreateEmbedderTaskRunner(
16 const FlutterTaskRunnerDescription* description) {
17 if (description == nullptr) {
18 return {};
19 }
20
21 if (SAFE_ACCESS(description, runs_task_on_current_thread_callback, nullptr) ==
22 nullptr) {
23 FML_LOG(ERROR) << "FlutterTaskRunnerDescription.runs_task_on_current_"
24 "thread_callback was nullptr.";
25 return {};
26 }
27
28 if (SAFE_ACCESS(description, post_task_callback, nullptr) == nullptr) {
29 FML_LOG(ERROR)
30 << "FlutterTaskRunnerDescription.post_task_callback was nullptr.";
31 return {};
32 }
33
34 auto user_data = SAFE_ACCESS(description, user_data, nullptr);
35
36 // ABI safety checks have been completed.
37 auto post_task_callback_c = description->post_task_callback;
38 auto runs_task_on_current_thread_callback_c =
39 description->runs_task_on_current_thread_callback;
40
41 EmbedderTaskRunner::DispatchTable task_runner_dispatch_table = {
42 // .post_task_callback
43 [post_task_callback_c, user_data](EmbedderTaskRunner* task_runner,
44 uint64_t task_baton,
45 fml::TimePoint target_time) -> void {
46 FlutterTask task = {
47 // runner
48 reinterpret_cast<FlutterTaskRunner>(task_runner),
49 // task
50 task_baton,
51 };
52 post_task_callback_c(task, target_time.ToEpochDelta().ToNanoseconds(),
53 user_data);
54 },
55 // runs_task_on_current_thread_callback
56 [runs_task_on_current_thread_callback_c, user_data]() -> bool {
57 return runs_task_on_current_thread_callback_c(user_data);
58 }};
59
60 return fml::MakeRefCounted<EmbedderTaskRunner>(task_runner_dispatch_table);
61 }
62
63 std::unique_ptr<EmbedderThreadHost>
CreateEmbedderOrEngineManagedThreadHost(const FlutterCustomTaskRunners * custom_task_runners)64 EmbedderThreadHost::CreateEmbedderOrEngineManagedThreadHost(
65 const FlutterCustomTaskRunners* custom_task_runners) {
66 {
67 auto host = CreateEmbedderManagedThreadHost(custom_task_runners);
68 if (host && host->IsValid()) {
69 return host;
70 }
71 }
72
73 // Only attempt to create the engine managed host if the embedder did not
74 // specify a custom configuration. We don't want to fallback to the engine
75 // managed configuration if the embedder attempted to specify a configuration
76 // but messed up with an incorrect configuration.
77 if (custom_task_runners == nullptr) {
78 auto host = CreateEngineManagedThreadHost();
79 if (host && host->IsValid()) {
80 return host;
81 }
82 }
83
84 return nullptr;
85 }
86
87 constexpr const char* kFlutterThreadName = "io.flutter";
88
89 // static
90 std::unique_ptr<EmbedderThreadHost>
CreateEmbedderManagedThreadHost(const FlutterCustomTaskRunners * custom_task_runners)91 EmbedderThreadHost::CreateEmbedderManagedThreadHost(
92 const FlutterCustomTaskRunners* custom_task_runners) {
93 if (custom_task_runners == nullptr) {
94 return nullptr;
95 }
96
97 const auto platform_task_runner = CreateEmbedderTaskRunner(
98 SAFE_ACCESS(custom_task_runners, platform_task_runner, nullptr));
99
100 // TODO(chinmaygarde): Add more here as we allow more threads to be controlled
101 // by the embedder. Create fallbacks as necessary.
102
103 if (!platform_task_runner) {
104 return nullptr;
105 }
106
107 ThreadHost thread_host(kFlutterThreadName, ThreadHost::Type::GPU |
108 ThreadHost::Type::IO |
109 ThreadHost::Type::UI);
110
111 flutter::TaskRunners task_runners(
112 kFlutterThreadName,
113 platform_task_runner, // platform
114 thread_host.gpu_thread->GetTaskRunner(), // gpu
115 thread_host.ui_thread->GetTaskRunner(), // ui
116 thread_host.io_thread->GetTaskRunner() // io
117 );
118
119 if (!task_runners.IsValid()) {
120 return nullptr;
121 }
122
123 std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners;
124 embedder_task_runners.insert(platform_task_runner);
125
126 auto embedder_host = std::make_unique<EmbedderThreadHost>(
127 std::move(thread_host), std::move(task_runners),
128 std::move(embedder_task_runners));
129
130 if (embedder_host->IsValid()) {
131 return embedder_host;
132 }
133
134 return nullptr;
135 }
136
137 // static
138 std::unique_ptr<EmbedderThreadHost>
CreateEngineManagedThreadHost()139 EmbedderThreadHost::CreateEngineManagedThreadHost() {
140 // Create a thread host with the current thread as the platform thread and all
141 // other threads managed.
142 ThreadHost thread_host(kFlutterThreadName, ThreadHost::Type::GPU |
143 ThreadHost::Type::IO |
144 ThreadHost::Type::UI);
145
146 fml::MessageLoop::EnsureInitializedForCurrentThread();
147
148 // For embedder platforms that don't have native message loop interop, this
149 // will reference a task runner that points to a null message loop
150 // implementation.
151 auto platform_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
152
153 flutter::TaskRunners task_runners(
154 kFlutterThreadName,
155 platform_task_runner, // platform
156 thread_host.gpu_thread->GetTaskRunner(), // gpu
157 thread_host.ui_thread->GetTaskRunner(), // ui
158 thread_host.io_thread->GetTaskRunner() // io
159 );
160
161 if (!task_runners.IsValid()) {
162 return nullptr;
163 }
164
165 std::set<fml::RefPtr<EmbedderTaskRunner>> empty_embedder_task_runners;
166
167 auto embedder_host = std::make_unique<EmbedderThreadHost>(
168 std::move(thread_host), std::move(task_runners),
169 empty_embedder_task_runners);
170
171 if (embedder_host->IsValid()) {
172 return embedder_host;
173 }
174
175 return nullptr;
176 }
177
EmbedderThreadHost(ThreadHost host,flutter::TaskRunners runners,std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners)178 EmbedderThreadHost::EmbedderThreadHost(
179 ThreadHost host,
180 flutter::TaskRunners runners,
181 std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners)
182 : host_(std::move(host)), runners_(std::move(runners)) {
183 for (const auto& runner : embedder_task_runners) {
184 runners_map_[reinterpret_cast<int64_t>(runner.get())] = runner;
185 }
186 }
187
188 EmbedderThreadHost::~EmbedderThreadHost() = default;
189
IsValid() const190 bool EmbedderThreadHost::IsValid() const {
191 return runners_.IsValid();
192 }
193
GetTaskRunners() const194 const flutter::TaskRunners& EmbedderThreadHost::GetTaskRunners() const {
195 return runners_;
196 }
197
PostTask(int64_t runner,uint64_t task) const198 bool EmbedderThreadHost::PostTask(int64_t runner, uint64_t task) const {
199 auto found = runners_map_.find(runner);
200 if (found == runners_map_.end()) {
201 return false;
202 }
203 return found->second->PostTask(task);
204 }
205
206 } // namespace flutter
207