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// FLUTTER_NOLINT
5
6#include "flutter/shell/common/isolate_configuration.h"
7
8#include "flutter/fml/make_copyable.h"
9#include "flutter/runtime/dart_vm.h"
10
11namespace flutter {
12
13IsolateConfiguration::IsolateConfiguration() = default;
14
15IsolateConfiguration::~IsolateConfiguration() = default;
16
17bool IsolateConfiguration::PrepareIsolate(DartIsolate& isolate) {
18 if (isolate.GetPhase() != DartIsolate::Phase::LibrariesSetup) {
19 FML_DLOG(ERROR)
20 << "Isolate was in incorrect phase to be prepared for running.";
21 return false;
22 }
23
24 return DoPrepareIsolate(isolate);
25}
26
27class AppSnapshotIsolateConfiguration final : public IsolateConfiguration {
28 public:
29 AppSnapshotIsolateConfiguration() = default;
30
31 // |IsolateConfiguration|
32 bool DoPrepareIsolate(DartIsolate& isolate) override {
33 return isolate.PrepareForRunningFromPrecompiledCode();
34 }
35
36 private:
37 FML_DISALLOW_COPY_AND_ASSIGN(AppSnapshotIsolateConfiguration);
38};
39
40class KernelIsolateConfiguration : public IsolateConfiguration {
41 public:
42 KernelIsolateConfiguration(std::unique_ptr<const fml::Mapping> kernel)
43 : kernel_(std::move(kernel)) {}
44
45 // |IsolateConfiguration|
46 bool DoPrepareIsolate(DartIsolate& isolate) override {
47 if (DartVM::IsRunningPrecompiledCode()) {
48 return false;
49 }
50 return isolate.PrepareForRunningFromKernel(std::move(kernel_));
51 }
52
53 private:
54 std::unique_ptr<const fml::Mapping> kernel_;
55
56 FML_DISALLOW_COPY_AND_ASSIGN(KernelIsolateConfiguration);
57};
58
59class KernelListIsolateConfiguration final : public IsolateConfiguration {
60 public:
61 KernelListIsolateConfiguration(
62 std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
63 kernel_pieces)
64 : kernel_pieces_(std::move(kernel_pieces)) {}
65
66 // |IsolateConfiguration|
67 bool DoPrepareIsolate(DartIsolate& isolate) override {
68 if (DartVM::IsRunningPrecompiledCode()) {
69 return false;
70 }
71
72 for (size_t i = 0; i < kernel_pieces_.size(); i++) {
73 bool last_piece = i + 1 == kernel_pieces_.size();
74
75 if (!isolate.PrepareForRunningFromKernel(kernel_pieces_[i].get(),
76 last_piece)) {
77 return false;
78 }
79 }
80
81 return true;
82 }
83
84 private:
85 std::vector<std::future<std::unique_ptr<const fml::Mapping>>> kernel_pieces_;
86
87 FML_DISALLOW_COPY_AND_ASSIGN(KernelListIsolateConfiguration);
88};
89
90static std::vector<std::string> ParseKernelListPaths(
91 std::unique_ptr<fml::Mapping> kernel_list) {
92 FML_DCHECK(kernel_list);
93
94 std::vector<std::string> kernel_pieces_paths;
95
96 const char* kernel_list_str =
97 reinterpret_cast<const char*>(kernel_list->GetMapping());
98 size_t kernel_list_size = kernel_list->GetSize();
99
100 size_t piece_path_start = 0;
101 while (piece_path_start < kernel_list_size) {
102 size_t piece_path_end = piece_path_start;
103 while ((piece_path_end < kernel_list_size) &&
104 (kernel_list_str[piece_path_end] != '\n')) {
105 piece_path_end++;
106 }
107 std::string piece_path(&kernel_list_str[piece_path_start],
108 piece_path_end - piece_path_start);
109 kernel_pieces_paths.emplace_back(std::move(piece_path));
110
111 piece_path_start = piece_path_end + 1;
112 }
113
114 return kernel_pieces_paths;
115}
116
117static std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
118PrepareKernelMappings(std::vector<std::string> kernel_pieces_paths,
119 std::shared_ptr<AssetManager> asset_manager,
120 fml::RefPtr<fml::TaskRunner> io_worker) {
121 FML_DCHECK(asset_manager);
122 std::vector<std::future<std::unique_ptr<const fml::Mapping>>> fetch_futures;
123
124 for (const auto& kernel_pieces_path : kernel_pieces_paths) {
125 std::promise<std::unique_ptr<const fml::Mapping>> fetch_promise;
126 fetch_futures.push_back(fetch_promise.get_future());
127 auto fetch_task =
128 fml::MakeCopyable([asset_manager, kernel_pieces_path,
129 fetch_promise = std::move(fetch_promise)]() mutable {
130 fetch_promise.set_value(
131 asset_manager->GetAsMapping(kernel_pieces_path));
132 });
133 // Fulfill the promise on the worker if one is available or the current
134 // thread if one is not.
135 if (io_worker) {
136 io_worker->PostTask(fetch_task);
137 } else {
138 fetch_task();
139 }
140 }
141
142 return fetch_futures;
143}
144
145std::unique_ptr<IsolateConfiguration> IsolateConfiguration::InferFromSettings(
146 const Settings& settings,
147 std::shared_ptr<AssetManager> asset_manager,
148 fml::RefPtr<fml::TaskRunner> io_worker) {
149 // Running in AOT mode.
150 if (DartVM::IsRunningPrecompiledCode()) {
151 return CreateForAppSnapshot();
152 }
153
154 if (!asset_manager) {
155 return nullptr;
156 }
157
158 if (settings.application_kernels) {
159 return CreateForKernelList(settings.application_kernels());
160 }
161
162 if (settings.application_kernel_asset.empty() &&
163 settings.application_kernel_list_asset.empty()) {
164 FML_DLOG(ERROR) << "application_kernel_asset or "
165 "application_kernel_list_asset must be set";
166 return nullptr;
167 }
168
169 // Running from kernel snapshot.
170 {
171 std::unique_ptr<fml::Mapping> kernel =
172 asset_manager->GetAsMapping(settings.application_kernel_asset);
173 if (kernel) {
174 return CreateForKernel(std::move(kernel));
175 }
176 }
177
178 // Running from kernel divided into several pieces (for sharing).
179 {
180 std::unique_ptr<fml::Mapping> kernel_list =
181 asset_manager->GetAsMapping(settings.application_kernel_list_asset);
182 if (!kernel_list) {
183 FML_LOG(ERROR) << "Failed to load: "
184 << settings.application_kernel_list_asset;
185 return nullptr;
186 }
187 auto kernel_pieces_paths = ParseKernelListPaths(std::move(kernel_list));
188 auto kernel_mappings = PrepareKernelMappings(std::move(kernel_pieces_paths),
189 asset_manager, io_worker);
190 return CreateForKernelList(std::move(kernel_mappings));
191 }
192
193 return nullptr;
194}
195
196std::unique_ptr<IsolateConfiguration>
197IsolateConfiguration::CreateForAppSnapshot() {
198 return std::make_unique<AppSnapshotIsolateConfiguration>();
199}
200
201std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernel(
202 std::unique_ptr<const fml::Mapping> kernel) {
203 return std::make_unique<KernelIsolateConfiguration>(std::move(kernel));
204}
205
206std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernelList(
207 std::vector<std::unique_ptr<const fml::Mapping>> kernel_pieces) {
208 std::vector<std::future<std::unique_ptr<const fml::Mapping>>> pieces;
209 for (auto& piece : kernel_pieces) {
210 std::promise<std::unique_ptr<const fml::Mapping>> promise;
211 pieces.push_back(promise.get_future());
212 promise.set_value(std::move(piece));
213 }
214 return CreateForKernelList(std::move(pieces));
215}
216
217std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernelList(
218 std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
219 kernel_pieces) {
220 return std::make_unique<KernelListIsolateConfiguration>(
221 std::move(kernel_pieces));
222}
223
224} // namespace flutter
225