• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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