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_safe_access.h"
13 
14 namespace 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 ///
29 static 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) {
46  FML_LOG(ERROR)
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 
82 std::unique_ptr<EmbedderThreadHost>
84  const FlutterCustomTaskRunners* custom_task_runners) {
85  {
86  auto host = CreateEmbedderManagedThreadHost(custom_task_runners);
87  if (host && host->IsValid()) {
88  return host;
89  }
90  }
91 
92  // Only attempt to create the engine managed host if the embedder did not
93  // specify a custom configuration. Don't fallback to the engine managed
94  // configuration if the embedder attempted to specify a configuration but
95  // messed up with an incorrect configuration.
96  if (custom_task_runners == nullptr) {
97  auto host = CreateEngineManagedThreadHost();
98  if (host && host->IsValid()) {
99  return host;
100  }
101  }
102 
103  return nullptr;
104 }
105 
109 }
110 
111 constexpr const char* kFlutterThreadName = "io.flutter";
112 
113 // static
114 std::unique_ptr<EmbedderThreadHost>
115 EmbedderThreadHost::CreateEmbedderManagedThreadHost(
116  const FlutterCustomTaskRunners* custom_task_runners) {
117  if (custom_task_runners == nullptr) {
118  return nullptr;
119  }
120 
121  // The UI and IO threads are always created by the engine and the embedder has
122  // no opportunity to specify task runners for the same.
123  //
124  // If/when more task runners are exposed, this mask will need to be updated.
125  uint64_t engine_thread_host_mask =
126  ThreadHost::Type::UI | ThreadHost::Type::IO;
127 
128  auto platform_task_runner_pair = CreateEmbedderTaskRunner(
129  SAFE_ACCESS(custom_task_runners, platform_task_runner, nullptr));
130  auto render_task_runner_pair = CreateEmbedderTaskRunner(
131  SAFE_ACCESS(custom_task_runners, render_task_runner, nullptr));
132 
133  if (!platform_task_runner_pair.first || !render_task_runner_pair.first) {
134  // User error while supplying a custom task runner. Return an invalid thread
135  // host. This will abort engine initialization. Don't fallback to defaults
136  // if the user wanted to specify a task runner but just messed up instead.
137  return nullptr;
138  }
139 
140  // If the embedder has not supplied a GPU task runner, one needs to be
141  // created.
142  if (!render_task_runner_pair.second) {
143  engine_thread_host_mask |= ThreadHost::Type::GPU;
144  }
145 
146  // If both the platform task runner and the GPU task runner are specified and
147  // have the same identifier, store only one.
148  if (platform_task_runner_pair.second && render_task_runner_pair.second) {
149  if (platform_task_runner_pair.second->GetEmbedderIdentifier() ==
150  render_task_runner_pair.second->GetEmbedderIdentifier()) {
151  render_task_runner_pair.second = platform_task_runner_pair.second;
152  }
153  }
154 
155  // Create a thread host with just the threads that need to be managed by the
156  // engine. The embedder has provided the rest.
157  ThreadHost thread_host(kFlutterThreadName, engine_thread_host_mask);
158 
159  // If the embedder has supplied a platform task runner, use that. If not, use
160  // the current thread task runner.
161  auto platform_task_runner = platform_task_runner_pair.second
162  ? static_cast<fml::RefPtr<fml::TaskRunner>>(
163  platform_task_runner_pair.second)
165 
166  // If the embedder has supplied a GPU task runner, use that. If not, use the
167  // one from our thread host.
168  auto render_task_runner = render_task_runner_pair.second
169  ? static_cast<fml::RefPtr<fml::TaskRunner>>(
170  render_task_runner_pair.second)
171  : thread_host.raster_thread->GetTaskRunner();
172 
173  flutter::TaskRunners task_runners(
174  kFlutterThreadName,
175  platform_task_runner, // platform
176  render_task_runner, // raster
177  thread_host.ui_thread->GetTaskRunner(), // ui (always engine managed)
178  thread_host.io_thread->GetTaskRunner() // io (always engine managed)
179  );
180 
181  if (!task_runners.IsValid()) {
182  return nullptr;
183  }
184 
185  std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners;
186 
187  if (platform_task_runner_pair.second) {
188  embedder_task_runners.insert(platform_task_runner_pair.second);
189  }
190 
191  if (render_task_runner_pair.second) {
192  embedder_task_runners.insert(render_task_runner_pair.second);
193  }
194 
195  auto embedder_host = std::make_unique<EmbedderThreadHost>(
196  std::move(thread_host), std::move(task_runners),
197  std::move(embedder_task_runners));
198 
199  if (embedder_host->IsValid()) {
200  return embedder_host;
201  }
202 
203  return nullptr;
204 }
205 
206 // static
207 std::unique_ptr<EmbedderThreadHost>
208 EmbedderThreadHost::CreateEngineManagedThreadHost() {
209  // Create a thread host with the current thread as the platform thread and all
210  // other threads managed.
211  ThreadHost thread_host(kFlutterThreadName, ThreadHost::Type::GPU |
212  ThreadHost::Type::IO |
213  ThreadHost::Type::UI);
214 
215  // For embedder platforms that don't have native message loop interop, this
216  // will reference a task runner that points to a null message loop
217  // implementation.
218  auto platform_task_runner = GetCurrentThreadTaskRunner();
219 
220  flutter::TaskRunners task_runners(
221  kFlutterThreadName,
222  platform_task_runner, // platform
223  thread_host.raster_thread->GetTaskRunner(), // raster
224  thread_host.ui_thread->GetTaskRunner(), // ui
225  thread_host.io_thread->GetTaskRunner() // io
226  );
227 
228  if (!task_runners.IsValid()) {
229  return nullptr;
230  }
231 
232  std::set<fml::RefPtr<EmbedderTaskRunner>> empty_embedder_task_runners;
233 
234  auto embedder_host = std::make_unique<EmbedderThreadHost>(
235  std::move(thread_host), std::move(task_runners),
236  empty_embedder_task_runners);
237 
238  if (embedder_host->IsValid()) {
239  return embedder_host;
240  }
241 
242  return nullptr;
243 }
244 
246  ThreadHost host,
247  flutter::TaskRunners runners,
248  std::set<fml::RefPtr<EmbedderTaskRunner>> embedder_task_runners)
249  : host_(std::move(host)), runners_(std::move(runners)) {
250  for (const auto& runner : embedder_task_runners) {
251  runners_map_[reinterpret_cast<int64_t>(runner.get())] = runner;
252  }
253 }
254 
256 
258  return runners_.IsValid();
259 }
260 
262  return runners_;
263 }
264 
265 bool EmbedderThreadHost::PostTask(int64_t runner, uint64_t task) const {
266  auto found = runners_map_.find(runner);
267  if (found == runners_map_.end()) {
268  return false;
269  }
270  return found->second->PostTask(task);
271 }
272 
273 } // namespace flutter
std::unique_ptr< fml::Thread > ui_thread
Definition: thread_host.h:26
static fml::RefPtr< fml::TaskRunner > GetCurrentThreadTaskRunner()
bool IsValid() const
Definition: task_runners.cc:46
EmbedderThreadHost(ThreadHost host, flutter::TaskRunners runners, std::set< fml::RefPtr< EmbedderTaskRunner >> embedder_task_runners)
Definition: ref_ptr.h:252
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
#define FML_LOG(severity)
Definition: logging.h:65
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
#define SAFE_ACCESS(pointer, member, default_value)
constexpr const char * kFlutterThreadName
G_BEGIN_DECLS FlValue gpointer user_data
The collection of all the threads used by the engine.
Definition: thread_host.h:16
static std::unique_ptr< EmbedderThreadHost > CreateEmbedderOrEngineManagedThreadHost(const FlutterCustomTaskRunners *custom_task_runners)
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...
std::unique_ptr< fml::Thread > io_thread
Definition: thread_host.h:28
const flutter::TaskRunners & GetTaskRunners() const
FlutterTaskRunnerPostTaskCallback post_task_callback
Definition: embedder.h:739
std::unique_ptr< fml::Thread > raster_thread
Definition: thread_host.h:27
BoolCallback runs_task_on_current_thread_callback
Definition: embedder.h:728
bool PostTask(int64_t runner, uint64_t task) const