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