Flutter Engine
 
Loading...
Searching...
No Matches
embedder_thread_host.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#define FML_USED_ON_EMBEDDER
6
8
9#include <algorithm>
10
13
14namespace flutter {
15
16std::set<intptr_t> EmbedderThreadHost::active_runners_;
17std::mutex EmbedderThreadHost::active_runners_mutex_;
18
19//------------------------------------------------------------------------------
20/// @brief Attempts to create a task runner from an embedder task runner
21/// description. The first boolean in the pair indicate whether the
22/// embedder specified an invalid task runner description. In this
23/// case, engine launch must be aborted. If the embedder did not
24/// specify any task runner, an engine managed task runner and
25/// thread must be selected instead.
26///
27/// @param[in] description The description
28///
29/// @return A pair that returns if the embedder has specified a task runner
30/// (null otherwise) and whether to terminate further engine launch.
31///
32static std::pair<bool, fml::RefPtr<EmbedderTaskRunner>>
34 if (description == nullptr) {
35 // This is not embedder error. The embedder API will just have to create a
36 // plain old task runner (and create a thread for it) instead of using a
37 // task runner provided to us by the embedder.
38 return {true, {}};
39 }
40
41 if (SAFE_ACCESS(description, runs_task_on_current_thread_callback, nullptr) ==
42 nullptr) {
43 FML_LOG(ERROR) << "FlutterTaskRunnerDescription.runs_task_on_current_"
44 "thread_callback was nullptr.";
45 return {false, {}};
46 }
47
48 if (SAFE_ACCESS(description, post_task_callback, nullptr) == nullptr) {
49 FML_LOG(ERROR)
50 << "FlutterTaskRunnerDescription.post_task_callback was nullptr.";
51 return {false, {}};
52 }
53
54 auto user_data = SAFE_ACCESS(description, user_data, nullptr);
55
56 // ABI safety checks have been completed.
57 auto post_task_callback_c = description->post_task_callback;
58 auto runs_task_on_current_thread_callback_c =
60
61 VoidCallback destruction_callback_c = [](void* user_data) {};
62 if (SAFE_ACCESS(description, destruction_callback, nullptr) != nullptr) {
63 destruction_callback_c = description->destruction_callback;
64 }
65
66 EmbedderTaskRunner::DispatchTable task_runner_dispatch_table = {
67 .post_task_callback = [post_task_callback_c, user_data](
68 EmbedderTaskRunner* task_runner,
69 uint64_t task_baton,
70 fml::TimePoint target_time) -> void {
71 FlutterTask task = {
72 // runner
73 reinterpret_cast<FlutterTaskRunner>(task_runner->unique_id()),
74 // task
75 task_baton,
76 };
77 post_task_callback_c(task, target_time.ToEpochDelta().ToNanoseconds(),
78 user_data);
79 },
80 .runs_task_on_current_thread_callback =
81 [runs_task_on_current_thread_callback_c, user_data]() -> bool {
82 return runs_task_on_current_thread_callback_c(user_data);
83 },
84 .destruction_callback =
85 [destruction_callback_c, user_data]() {
86 destruction_callback_c(user_data);
87 },
88 };
89
90 return {true, fml::MakeRefCounted<EmbedderTaskRunner>(
91 task_runner_dispatch_table,
92 SAFE_ACCESS(description, identifier, 0u))};
93}
94
95std::unique_ptr<EmbedderThreadHost>
97 const FlutterCustomTaskRunners* custom_task_runners,
98 const flutter::ThreadConfigSetter& config_setter) {
99 {
100 auto host =
101 CreateEmbedderManagedThreadHost(custom_task_runners, config_setter);
102 if (host && host->IsValid()) {
103 return host;
104 }
105 }
106
107 // Only attempt to create the engine managed host if the embedder did not
108 // specify a custom configuration. Don't fallback to the engine managed
109 // configuration if the embedder attempted to specify a configuration but
110 // messed up with an incorrect configuration.
111 if (custom_task_runners == nullptr) {
112 auto host = CreateEngineManagedThreadHost(config_setter);
113 if (host && host->IsValid()) {
114 return host;
115 }
116 }
117
118 return nullptr;
119}
120
125
126constexpr const char* kFlutterThreadName = "io.flutter";
127
136
137// static
138std::unique_ptr<EmbedderThreadHost>
139EmbedderThreadHost::CreateEmbedderManagedThreadHost(
140 const FlutterCustomTaskRunners* custom_task_runners,
141 const flutter::ThreadConfigSetter& config_setter) {
142 if (custom_task_runners == nullptr) {
143 return nullptr;
144 }
145
146 auto thread_host_config = ThreadHost::ThreadHostConfig(config_setter);
147
148 // The IO threads are always created by the engine and the embedder has
149 // no opportunity to specify task runners for the same.
150 //
151 // If/when more task runners are exposed, this mask will need to be updated.
152 thread_host_config.SetIOConfig(MakeThreadConfig(
154
155 auto ui_task_runner_pair = CreateEmbedderTaskRunner(
156 SAFE_ACCESS(custom_task_runners, ui_task_runner, nullptr));
157 auto platform_task_runner_pair = CreateEmbedderTaskRunner(
158 SAFE_ACCESS(custom_task_runners, platform_task_runner, nullptr));
159 auto render_task_runner_pair = CreateEmbedderTaskRunner(
160 SAFE_ACCESS(custom_task_runners, render_task_runner, nullptr));
161
162 if (!platform_task_runner_pair.first || !render_task_runner_pair.first) {
163 // User error while supplying a custom task runner. Return an invalid thread
164 // host. This will abort engine initialization. Don't fallback to defaults
165 // if the user wanted to specify a task runner but just messed up instead.
166 return nullptr;
167 }
168
169 // If the embedder has not supplied a UI task runner, one needs to be created.
170 if (!ui_task_runner_pair.second) {
171 thread_host_config.SetUIConfig(MakeThreadConfig(
173 }
174
175 // If the embedder has not supplied a raster task runner, one needs to be
176 // created.
177 if (!render_task_runner_pair.second) {
178 thread_host_config.SetRasterConfig(MakeThreadConfig(
180 }
181
182 // If both the platform task runner and the raster task runner are specified
183 // and have the same identifier, store only one.
184 if (platform_task_runner_pair.second && render_task_runner_pair.second) {
185 if (platform_task_runner_pair.second->GetEmbedderIdentifier() ==
186 render_task_runner_pair.second->GetEmbedderIdentifier()) {
187 render_task_runner_pair.second = platform_task_runner_pair.second;
188 }
189 }
190
191 // If both platform task runner and UI task runner are specified and have
192 // the same identifier, store only one.
193 if (platform_task_runner_pair.second && ui_task_runner_pair.second) {
194 if (platform_task_runner_pair.second->GetEmbedderIdentifier() ==
195 ui_task_runner_pair.second->GetEmbedderIdentifier()) {
196 ui_task_runner_pair.second = platform_task_runner_pair.second;
197 }
198 }
199
200 // Create a thread host with just the threads that need to be managed by the
201 // engine. The embedder has provided the rest.
202 ThreadHost thread_host(thread_host_config);
203
204 // If the embedder has supplied a platform task runner, use that. If not, use
205 // the current thread task runner.
206 auto platform_task_runner = platform_task_runner_pair.second
207 ? static_cast<fml::RefPtr<fml::TaskRunner>>(
208 platform_task_runner_pair.second)
210
211 // If the embedder has supplied a raster task runner, use that. If not, use
212 // the one from our thread host.
213 auto render_task_runner = render_task_runner_pair.second
214 ? static_cast<fml::RefPtr<fml::TaskRunner>>(
215 render_task_runner_pair.second)
216 : thread_host.raster_thread->GetTaskRunner();
217
218 auto ui_task_runner = ui_task_runner_pair.second
219 ? static_cast<fml::RefPtr<fml::TaskRunner>>(
220 ui_task_runner_pair.second)
221 : thread_host.ui_thread->GetTaskRunner();
222
223 flutter::TaskRunners task_runners(
225 platform_task_runner, // platform
226 render_task_runner, // raster
227 ui_task_runner, // ui
228 thread_host.io_thread->GetTaskRunner() // io (always engine managed)
229 );
230
231 if (!task_runners.IsValid()) {
232 return nullptr;
233 }
234
235 std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners;
236
237 if (platform_task_runner_pair.second) {
238 embedder_task_runners.insert(platform_task_runner_pair.second);
239 }
240
241 if (render_task_runner_pair.second) {
242 embedder_task_runners.insert(render_task_runner_pair.second);
243 }
244
245 if (ui_task_runner_pair.second) {
246 embedder_task_runners.insert(ui_task_runner_pair.second);
247 }
248
249 auto embedder_host = std::make_unique<EmbedderThreadHost>(
250 std::move(thread_host), std::move(task_runners),
251 std::move(embedder_task_runners));
252
253 if (embedder_host->IsValid()) {
254 return embedder_host;
255 }
256
257 return nullptr;
258 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
259}
260
261// static
262std::unique_ptr<EmbedderThreadHost>
263EmbedderThreadHost::CreateEngineManagedThreadHost(
264 const flutter::ThreadConfigSetter& config_setter) {
265 // Crate a thraed host config, and specified the thread name and priority.
266 auto thread_host_config = ThreadHost::ThreadHostConfig(config_setter);
267 thread_host_config.SetUIConfig(MakeThreadConfig(
269 thread_host_config.SetRasterConfig(MakeThreadConfig(
271 thread_host_config.SetIOConfig(MakeThreadConfig(
273
274 // Create a thread host with the current thread as the platform thread and all
275 // other threads managed.
276 ThreadHost thread_host(thread_host_config);
277
278 // For embedder platforms that don't have native message loop interop, this
279 // will reference a task runner that points to a null message loop
280 // implementation.
281 auto platform_task_runner = GetCurrentThreadTaskRunner();
282
283 flutter::TaskRunners task_runners(
285 platform_task_runner, // platform
286 thread_host.raster_thread->GetTaskRunner(), // raster
287 thread_host.ui_thread->GetTaskRunner(), // ui
288 thread_host.io_thread->GetTaskRunner() // io
289 );
290
291 if (!task_runners.IsValid()) {
292 return nullptr;
293 }
294
295 std::set<fml::RefPtr<EmbedderTaskRunner>> empty_embedder_task_runners;
296
297 auto embedder_host = std::make_unique<EmbedderThreadHost>(
298 std::move(thread_host), std::move(task_runners),
299 empty_embedder_task_runners);
300
301 if (embedder_host->IsValid()) {
302 return embedder_host;
303 }
304
305 return nullptr;
306}
307
310 const flutter::TaskRunners& runners,
311 const std::set<fml::RefPtr<EmbedderTaskRunner>>& embedder_task_runners)
312 : host_(std::move(host)), runners_(runners) {
313 std::lock_guard guard(active_runners_mutex_);
314 for (const auto& runner : embedder_task_runners) {
315 runners_map_[runner->unique_id()] = runner;
316 active_runners_.insert(runner->unique_id());
317 }
318}
319
321
323 std::lock_guard guard(active_runners_mutex_);
324 for (const auto& runner : runners_map_) {
325 active_runners_.erase(runner.first);
326 }
327}
328
330 std::lock_guard guard(active_runners_mutex_);
331 return active_runners_.find(runner) != active_runners_.end();
332}
333
335 return runners_.IsValid();
336}
337
339 return runners_;
340}
341
342bool EmbedderThreadHost::PostTask(intptr_t runner, uint64_t task) const {
343 auto found = runners_map_.find(runner);
344 if (found == runners_map_.end()) {
345 return false;
346 }
347 return found->second->PostTask(task);
348}
349
350} // namespace flutter
GLenum type
bool PostTask(intptr_t runner, uint64_t task) const
static bool RunnerIsValid(intptr_t runner)
const flutter::TaskRunners & GetTaskRunners() const
static std::unique_ptr< EmbedderThreadHost > CreateEmbedderOrEngineManagedThreadHost(const FlutterCustomTaskRunners *custom_task_runners, const flutter::ThreadConfigSetter &config_setter=fml::Thread::SetCurrentThreadName)
EmbedderThreadHost(ThreadHost host, const flutter::TaskRunners &runners, const std::set< fml::RefPtr< EmbedderTaskRunner > > &embedder_task_runners)
static void EnsureInitializedForCurrentThread()
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
ThreadPriority
Valid values for priority of Thread.
Definition thread.h:23
@ kRaster
Suitable for thread which raster data.
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
@ kDisplay
Suitable for threads which generate data for the display.
void(* VoidCallback)(void *)
Definition embedder.h:409
struct _FlutterTaskRunner * FlutterTaskRunner
Definition embedder.h:1846
#define SAFE_ACCESS(pointer, member, default_value)
#define FML_LOG(severity)
Definition logging.h:101
fml::Thread::ThreadConfig MakeThreadConfig(flutter::ThreadHost::Type type, fml::Thread::ThreadPriority priority)
static fml::RefPtr< fml::TaskRunner > GetCurrentThreadTaskRunner()
constexpr const char * kFlutterThreadName
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service host
Definition switch_defs.h:69
fml::Thread::ThreadConfigSetter ThreadConfigSetter
Definition thread_host.h:18
static std::pair< bool, fml::RefPtr< EmbedderTaskRunner > > CreateEmbedderTaskRunner(const FlutterTaskRunnerDescription *description)
Attempts to create a task runner from an embedder task runner description. The first boolean in the p...
Definition ref_ptr.h:261
BoolCallback runs_task_on_current_thread_callback
Definition embedder.h:1870
FlutterTaskRunnerPostTaskCallback post_task_callback
Definition embedder.h:1881
VoidCallback destruction_callback
The callback invoked when the task runner is destroyed.
Definition embedder.h:1886
std::function< void(EmbedderTaskRunner *task_runner, uint64_t task_baton, fml::TimePoint target_time)> post_task_callback
static std::string MakeThreadName(Type type, const std::string &prefix)
Use the prefix and thread type to generator a thread name.
The collection of all the threads used by the engine.
Definition thread_host.h:21
The ThreadConfig is the thread info include thread name, thread priority.
Definition thread.h:35