Flutter Engine
The Flutter Engine
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
7#include "flutter/shell/platform/embedder/embedder_thread_host.h"
8
9#include <algorithm>
10
11#include "flutter/fml/message_loop.h"
12#include "flutter/shell/platform/embedder/embedder_struct_macros.h"
13
14namespace flutter {
15
16//------------------------------------------------------------------------------
17/// @brief Attempts to create a task runner from an embedder task runner
18/// description. The first boolean in the pair indicate whether the
19/// embedder specified an invalid task runner description. In this
20/// case, engine launch must be aborted. If the embedder did not
21/// specify any task runner, an engine managed task runner and
22/// thread must be selected instead.
23///
24/// @param[in] description The description
25///
26/// @return A pair that returns if the embedder has specified a task runner
27/// (null otherwise) and whether to terminate further engine launch.
28///
29static std::pair<bool, fml::RefPtr<EmbedderTaskRunner>>
31 if (description == nullptr) {
32 // This is not embedder error. The embedder API will just have to create a
33 // plain old task runner (and create a thread for it) instead of using a
34 // task runner provided to us by the embedder.
35 return {true, {}};
36 }
37
38 if (SAFE_ACCESS(description, runs_task_on_current_thread_callback, nullptr) ==
39 nullptr) {
40 FML_LOG(ERROR) << "FlutterTaskRunnerDescription.runs_task_on_current_"
41 "thread_callback was nullptr.";
42 return {false, {}};
43 }
44
45 if (SAFE_ACCESS(description, post_task_callback, nullptr) == nullptr) {
47 << "FlutterTaskRunnerDescription.post_task_callback was nullptr.";
48 return {false, {}};
49 }
50
51 auto user_data = SAFE_ACCESS(description, user_data, nullptr);
52
53 // ABI safety checks have been completed.
54 auto post_task_callback_c = description->post_task_callback;
55 auto runs_task_on_current_thread_callback_c =
57
58 EmbedderTaskRunner::DispatchTable task_runner_dispatch_table = {
59 // .post_task_callback
60 [post_task_callback_c, user_data](EmbedderTaskRunner* task_runner,
61 uint64_t task_baton,
62 fml::TimePoint target_time) -> void {
63 FlutterTask task = {
64 // runner
65 reinterpret_cast<FlutterTaskRunner>(task_runner),
66 // task
67 task_baton,
68 };
69 post_task_callback_c(task, target_time.ToEpochDelta().ToNanoseconds(),
70 user_data);
71 },
72 // runs_task_on_current_thread_callback
73 [runs_task_on_current_thread_callback_c, user_data]() -> bool {
74 return runs_task_on_current_thread_callback_c(user_data);
75 }};
76
77 return {true, fml::MakeRefCounted<EmbedderTaskRunner>(
78 task_runner_dispatch_table,
79 SAFE_ACCESS(description, identifier, 0u))};
80}
81
82std::unique_ptr<EmbedderThreadHost>
84 const FlutterCustomTaskRunners* custom_task_runners,
85 const flutter::ThreadConfigSetter& config_setter) {
86 {
87 auto host =
88 CreateEmbedderManagedThreadHost(custom_task_runners, config_setter);
89 if (host && host->IsValid()) {
90 return host;
91 }
92 }
93
94 // Only attempt to create the engine managed host if the embedder did not
95 // specify a custom configuration. Don't fallback to the engine managed
96 // configuration if the embedder attempted to specify a configuration but
97 // messed up with an incorrect configuration.
98 if (custom_task_runners == nullptr) {
99 auto host = CreateEngineManagedThreadHost(config_setter);
100 if (host && host->IsValid()) {
101 return host;
102 }
103 }
104
105 return nullptr;
106}
107
111}
112
113constexpr const char* kFlutterThreadName = "io.flutter";
114
121 priority);
122}
123
124// static
125std::unique_ptr<EmbedderThreadHost>
126EmbedderThreadHost::CreateEmbedderManagedThreadHost(
127 const FlutterCustomTaskRunners* custom_task_runners,
128 const flutter::ThreadConfigSetter& config_setter) {
129 if (custom_task_runners == nullptr) {
130 return nullptr;
131 }
132
133 auto thread_host_config = ThreadHost::ThreadHostConfig(config_setter);
134
135 // The UI and IO threads are always created by the engine and the embedder has
136 // no opportunity to specify task runners for the same.
137 //
138 // If/when more task runners are exposed, this mask will need to be updated.
139 thread_host_config.SetUIConfig(MakeThreadConfig(
140 ThreadHost::Type::kUi, fml::Thread::ThreadPriority::kDisplay));
141 thread_host_config.SetIOConfig(MakeThreadConfig(
142 ThreadHost::Type::kIo, fml::Thread::ThreadPriority::kBackground));
143
144 auto platform_task_runner_pair = CreateEmbedderTaskRunner(
145 SAFE_ACCESS(custom_task_runners, platform_task_runner, nullptr));
146 auto render_task_runner_pair = CreateEmbedderTaskRunner(
147 SAFE_ACCESS(custom_task_runners, render_task_runner, nullptr));
148
149 if (!platform_task_runner_pair.first || !render_task_runner_pair.first) {
150 // User error while supplying a custom task runner. Return an invalid thread
151 // host. This will abort engine initialization. Don't fallback to defaults
152 // if the user wanted to specify a task runner but just messed up instead.
153 return nullptr;
154 }
155
156 // If the embedder has not supplied a raster task runner, one needs to be
157 // created.
158 if (!render_task_runner_pair.second) {
159 thread_host_config.SetRasterConfig(MakeThreadConfig(
161 }
162
163 // If both the platform task runner and the raster task runner are specified
164 // and have the same identifier, store only one.
165 if (platform_task_runner_pair.second && render_task_runner_pair.second) {
166 if (platform_task_runner_pair.second->GetEmbedderIdentifier() ==
167 render_task_runner_pair.second->GetEmbedderIdentifier()) {
168 render_task_runner_pair.second = platform_task_runner_pair.second;
169 }
170 }
171
172 // Create a thread host with just the threads that need to be managed by the
173 // engine. The embedder has provided the rest.
174 ThreadHost thread_host(thread_host_config);
175
176 // If the embedder has supplied a platform task runner, use that. If not, use
177 // the current thread task runner.
178 auto platform_task_runner = platform_task_runner_pair.second
179 ? static_cast<fml::RefPtr<fml::TaskRunner>>(
180 platform_task_runner_pair.second)
182
183 // If the embedder has supplied a raster task runner, use that. If not, use
184 // the one from our thread host.
185 auto render_task_runner = render_task_runner_pair.second
186 ? static_cast<fml::RefPtr<fml::TaskRunner>>(
187 render_task_runner_pair.second)
188 : thread_host.raster_thread->GetTaskRunner();
189
190 flutter::TaskRunners task_runners(
192 platform_task_runner, // platform
193 render_task_runner, // raster
194 thread_host.ui_thread->GetTaskRunner(), // ui (always engine managed)
195 thread_host.io_thread->GetTaskRunner() // io (always engine managed)
196 );
197
198 if (!task_runners.IsValid()) {
199 return nullptr;
200 }
201
202 std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners;
203
204 if (platform_task_runner_pair.second) {
205 embedder_task_runners.insert(platform_task_runner_pair.second);
206 }
207
208 if (render_task_runner_pair.second) {
209 embedder_task_runners.insert(render_task_runner_pair.second);
210 }
211
212 auto embedder_host = std::make_unique<EmbedderThreadHost>(
213 std::move(thread_host), std::move(task_runners),
214 std::move(embedder_task_runners));
215
216 if (embedder_host->IsValid()) {
217 return embedder_host;
218 }
219
220 return nullptr;
221}
222
223// static
224std::unique_ptr<EmbedderThreadHost>
225EmbedderThreadHost::CreateEngineManagedThreadHost(
226 const flutter::ThreadConfigSetter& config_setter) {
227 // Crate a thraed host config, and specified the thread name and priority.
228 auto thread_host_config = ThreadHost::ThreadHostConfig(config_setter);
229 thread_host_config.SetUIConfig(MakeThreadConfig(
231 thread_host_config.SetRasterConfig(MakeThreadConfig(
233 thread_host_config.SetIOConfig(MakeThreadConfig(
235
236 // Create a thread host with the current thread as the platform thread and all
237 // other threads managed.
238 ThreadHost thread_host(thread_host_config);
239
240 // For embedder platforms that don't have native message loop interop, this
241 // will reference a task runner that points to a null message loop
242 // implementation.
243 auto platform_task_runner = GetCurrentThreadTaskRunner();
244
245 flutter::TaskRunners task_runners(
247 platform_task_runner, // platform
248 thread_host.raster_thread->GetTaskRunner(), // raster
249 thread_host.ui_thread->GetTaskRunner(), // ui
250 thread_host.io_thread->GetTaskRunner() // io
251 );
252
253 if (!task_runners.IsValid()) {
254 return nullptr;
255 }
256
257 std::set<fml::RefPtr<EmbedderTaskRunner>> empty_embedder_task_runners;
258
259 auto embedder_host = std::make_unique<EmbedderThreadHost>(
260 std::move(thread_host), std::move(task_runners),
261 empty_embedder_task_runners);
262
263 if (embedder_host->IsValid()) {
264 return embedder_host;
265 }
266
267 return nullptr;
268}
269
272 const flutter::TaskRunners& runners,
273 const std::set<fml::RefPtr<EmbedderTaskRunner>>& embedder_task_runners)
274 : host_(std::move(host)), runners_(runners) {
275 for (const auto& runner : embedder_task_runners) {
276 runners_map_[reinterpret_cast<int64_t>(runner.get())] = runner;
277 }
278}
279
281
283 return runners_.IsValid();
284}
285
287 return runners_;
288}
289
290bool EmbedderThreadHost::PostTask(int64_t runner, uint64_t task) const {
291 auto found = runners_map_.find(runner);
292 if (found == runners_map_.end()) {
293 return false;
294 }
295 return found->second->PostTask(task);
296}
297
298} // namespace flutter
GLenum type
bool PostTask(int64_t runner, uint64_t task) const
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)
bool IsValid() const
Definition: task_runners.cc:46
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
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.
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
@ kRaster
Suitable for thread which raster data.
Definition: embedder.h:266
#define SAFE_ACCESS(pointer, member, default_value)
#define FML_LOG(severity)
Definition: logging.h:82
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: switches.h:74
fml::Thread::ThreadConfig ThreadConfig
Definition: thread_host.h:17
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...
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 The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
Definition: ref_ptr.h:256
BoolCallback runs_task_on_current_thread_callback
Definition: embedder.h:1572
FlutterTaskRunnerPostTaskCallback post_task_callback
Definition: embedder.h:1583
static std::string MakeThreadName(Type type, const std::string &prefix)
Use the prefix and thread type to generator a thread name.
Definition: thread_host.cc:15
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
void * user_data
#define ERROR(message)
Definition: elf_loader.cc:260