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#include "flutter/runtime/isolate_configuration.h"
6
7#include "flutter/fml/make_copyable.h"
8#include "flutter/runtime/dart_vm.h"
9
10namespace flutter {
11
12IsolateConfiguration::IsolateConfiguration() = default;
13
14IsolateConfiguration::~IsolateConfiguration() = default;
15
16bool IsolateConfiguration::PrepareIsolate(DartIsolate& isolate) {
17 if (isolate.GetPhase() != DartIsolate::Phase::LibrariesSetup) {
18 FML_DLOG(ERROR)
19 << "Isolate was in incorrect phase to be prepared for running.";
20 return false;
21 }
22
23 return DoPrepareIsolate(isolate);
24}
25
26class AppSnapshotIsolateConfiguration final : public IsolateConfiguration {
27 public:
28 AppSnapshotIsolateConfiguration() = default;
29
30 // |IsolateConfiguration|
31 bool DoPrepareIsolate(DartIsolate& isolate) override {
32 return isolate.PrepareForRunningFromPrecompiledCode();
33 }
34
35 // |IsolateConfiguration|
36 bool IsNullSafetyEnabled(const DartSnapshot& snapshot) override {
37 return snapshot.IsNullSafetyEnabled(application_kernel_mapping: nullptr);
38 }
39
40 private:
41 FML_DISALLOW_COPY_AND_ASSIGN(AppSnapshotIsolateConfiguration);
42};
43
44class KernelIsolateConfiguration : public IsolateConfiguration {
45 public:
46 explicit KernelIsolateConfiguration(
47 std::unique_ptr<const fml::Mapping> kernel)
48 : kernel_(std::move(kernel)) {}
49
50 // |IsolateConfiguration|
51 bool DoPrepareIsolate(DartIsolate& isolate) override {
52 if (DartVM::IsRunningPrecompiledCode()) {
53 return false;
54 }
55 return isolate.PrepareForRunningFromKernel(kernel: std::move(kernel_),
56 /*child_isolate=*/false,
57 /*last_piece=*/true);
58 }
59
60 // |IsolateConfiguration|
61 bool IsNullSafetyEnabled(const DartSnapshot& snapshot) override {
62 return snapshot.IsNullSafetyEnabled(application_kernel_mapping: kernel_.get());
63 }
64
65 private:
66 std::unique_ptr<const fml::Mapping> kernel_;
67
68 FML_DISALLOW_COPY_AND_ASSIGN(KernelIsolateConfiguration);
69};
70
71class KernelListIsolateConfiguration final : public IsolateConfiguration {
72 public:
73 explicit KernelListIsolateConfiguration(
74 std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
75 kernel_pieces)
76 : kernel_piece_futures_(std::move(kernel_pieces)) {
77 if (kernel_piece_futures_.empty()) {
78 FML_LOG(ERROR) << "Attempted to create kernel list configuration without "
79 "any kernel blobs.";
80 }
81 }
82
83 // |IsolateConfiguration|
84 bool DoPrepareIsolate(DartIsolate& isolate) override {
85 if (DartVM::IsRunningPrecompiledCode()) {
86 return false;
87 }
88
89 ResolveKernelPiecesIfNecessary();
90
91 if (resolved_kernel_pieces_.empty()) {
92 FML_DLOG(ERROR) << "No kernel pieces provided to prepare this isolate.";
93 return false;
94 }
95
96 for (size_t i = 0; i < resolved_kernel_pieces_.size(); i++) {
97 if (!resolved_kernel_pieces_[i]) {
98 FML_DLOG(ERROR) << "This kernel list isolate configuration was already "
99 "used to prepare an isolate.";
100 return false;
101 }
102 const bool last_piece = i + 1 == resolved_kernel_pieces_.size();
103 if (!isolate.PrepareForRunningFromKernel(
104 kernel: std::move(resolved_kernel_pieces_[i]), /*child_isolate=*/false,
105 last_piece)) {
106 return false;
107 }
108 }
109
110 return true;
111 }
112
113 // |IsolateConfiguration|
114 bool IsNullSafetyEnabled(const DartSnapshot& snapshot) override {
115 ResolveKernelPiecesIfNecessary();
116 const auto kernel = resolved_kernel_pieces_.empty()
117 ? nullptr
118 : resolved_kernel_pieces_.front().get();
119 return snapshot.IsNullSafetyEnabled(application_kernel_mapping: kernel);
120 }
121
122 // This must be call as late as possible before accessing any of the kernel
123 // pieces. This will delay blocking on the futures for as long as possible. So
124 // far, only Fuchsia depends on this optimization and only on the non-AOT
125 // configs.
126 void ResolveKernelPiecesIfNecessary() {
127 if (resolved_kernel_pieces_.size() == kernel_piece_futures_.size()) {
128 return;
129 }
130
131 resolved_kernel_pieces_.clear();
132 for (auto& piece : kernel_piece_futures_) {
133 // The get() call will xfer the unique pointer out and leave an empty
134 // future in the original vector.
135 resolved_kernel_pieces_.emplace_back(args: piece.get());
136 }
137 }
138
139 private:
140 std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
141 kernel_piece_futures_;
142 std::vector<std::unique_ptr<const fml::Mapping>> resolved_kernel_pieces_;
143
144 FML_DISALLOW_COPY_AND_ASSIGN(KernelListIsolateConfiguration);
145};
146
147static std::vector<std::string> ParseKernelListPaths(
148 std::unique_ptr<fml::Mapping> kernel_list) {
149 FML_DCHECK(kernel_list);
150
151 std::vector<std::string> kernel_pieces_paths;
152
153 const char* kernel_list_str =
154 reinterpret_cast<const char*>(kernel_list->GetMapping());
155 size_t kernel_list_size = kernel_list->GetSize();
156
157 size_t piece_path_start = 0;
158 while (piece_path_start < kernel_list_size) {
159 size_t piece_path_end = piece_path_start;
160 while ((piece_path_end < kernel_list_size) &&
161 (kernel_list_str[piece_path_end] != '\n')) {
162 piece_path_end++;
163 }
164 std::string piece_path(&kernel_list_str[piece_path_start],
165 piece_path_end - piece_path_start);
166 kernel_pieces_paths.emplace_back(args: std::move(piece_path));
167
168 piece_path_start = piece_path_end + 1;
169 }
170
171 return kernel_pieces_paths;
172}
173
174static std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
175PrepareKernelMappings(const std::vector<std::string>& kernel_pieces_paths,
176 const std::shared_ptr<AssetManager>& asset_manager,
177 const fml::RefPtr<fml::TaskRunner>& io_worker) {
178 FML_DCHECK(asset_manager);
179 std::vector<std::future<std::unique_ptr<const fml::Mapping>>> fetch_futures;
180
181 for (const auto& kernel_pieces_path : kernel_pieces_paths) {
182 std::promise<std::unique_ptr<const fml::Mapping>> fetch_promise;
183 fetch_futures.push_back(x: fetch_promise.get_future());
184 auto fetch_task =
185 fml::MakeCopyable(lambda: [asset_manager, kernel_pieces_path,
186 fetch_promise = std::move(fetch_promise)]() mutable {
187 fetch_promise.set_value(
188 asset_manager->GetAsMapping(asset_name: kernel_pieces_path));
189 });
190 // Fulfill the promise on the worker if one is available or the current
191 // thread if one is not.
192 if (io_worker) {
193 io_worker->PostTask(task: fetch_task);
194 } else {
195 fetch_task();
196 }
197 }
198
199 return fetch_futures;
200}
201
202std::unique_ptr<IsolateConfiguration> IsolateConfiguration::InferFromSettings(
203 const Settings& settings,
204 const std::shared_ptr<AssetManager>& asset_manager,
205 const fml::RefPtr<fml::TaskRunner>& io_worker) {
206 // Running in AOT mode.
207 if (DartVM::IsRunningPrecompiledCode()) {
208 return CreateForAppSnapshot();
209 }
210
211 if (settings.application_kernels) {
212 return CreateForKernelList(kernel_pieces: settings.application_kernels());
213 }
214
215 if (settings.application_kernel_asset.empty() &&
216 settings.application_kernel_list_asset.empty()) {
217 FML_DLOG(ERROR) << "application_kernel_asset or "
218 "application_kernel_list_asset must be set";
219 return nullptr;
220 }
221
222 if (!asset_manager) {
223 FML_DLOG(ERROR) << "No asset manager specified when attempting to create "
224 "isolate configuration.";
225 return nullptr;
226 }
227
228 // Running from kernel snapshot. Requires asset manager.
229 {
230 std::unique_ptr<fml::Mapping> kernel =
231 asset_manager->GetAsMapping(asset_name: settings.application_kernel_asset);
232 if (kernel) {
233 return CreateForKernel(kernel: std::move(kernel));
234 }
235 }
236
237 // Running from kernel divided into several pieces (for sharing). Requires
238 // asset manager and io worker.
239
240 if (!io_worker) {
241 FML_DLOG(ERROR) << "No IO worker specified to load kernel pieces.";
242 return nullptr;
243 }
244
245 {
246 std::unique_ptr<fml::Mapping> kernel_list =
247 asset_manager->GetAsMapping(asset_name: settings.application_kernel_list_asset);
248 if (!kernel_list) {
249 FML_LOG(ERROR) << "Failed to load: "
250 << settings.application_kernel_list_asset;
251 return nullptr;
252 }
253 auto kernel_pieces_paths = ParseKernelListPaths(kernel_list: std::move(kernel_list));
254 auto kernel_mappings =
255 PrepareKernelMappings(kernel_pieces_paths, asset_manager, io_worker);
256 return CreateForKernelList(kernel_pieces: std::move(kernel_mappings));
257 }
258
259 return nullptr;
260}
261
262std::unique_ptr<IsolateConfiguration>
263IsolateConfiguration::CreateForAppSnapshot() {
264 return std::make_unique<AppSnapshotIsolateConfiguration>();
265}
266
267std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernel(
268 std::unique_ptr<const fml::Mapping> kernel) {
269 return std::make_unique<KernelIsolateConfiguration>(args: std::move(kernel));
270}
271
272std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernelList(
273 std::vector<std::unique_ptr<const fml::Mapping>> kernel_pieces) {
274 std::vector<std::future<std::unique_ptr<const fml::Mapping>>> pieces;
275 for (auto& piece : kernel_pieces) {
276 if (!piece) {
277 FML_DLOG(ERROR) << "Invalid kernel piece.";
278 continue;
279 }
280 std::promise<std::unique_ptr<const fml::Mapping>> promise;
281 pieces.push_back(x: promise.get_future());
282 promise.set_value(std::move(piece));
283 }
284 return CreateForKernelList(kernel_pieces: std::move(pieces));
285}
286
287std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernelList(
288 std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
289 kernel_pieces) {
290 return std::make_unique<KernelListIsolateConfiguration>(
291 args: std::move(kernel_pieces));
292}
293
294} // namespace flutter
295

source code of flutter_engine/flutter/runtime/isolate_configuration.cc