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 | |
11 | namespace flutter { |
12 | |
13 | IsolateConfiguration::IsolateConfiguration() = default; |
14 | |
15 | IsolateConfiguration::~IsolateConfiguration() = default; |
16 | |
17 | bool 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 | |
27 | class 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 | |
40 | class 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 | |
59 | class 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 | |
90 | static 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 | |
117 | static std::vector<std::future<std::unique_ptr<const fml::Mapping>>> |
118 | PrepareKernelMappings(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 | |
145 | std::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 | |
196 | std::unique_ptr<IsolateConfiguration> |
197 | IsolateConfiguration::CreateForAppSnapshot() { |
198 | return std::make_unique<AppSnapshotIsolateConfiguration>(); |
199 | } |
200 | |
201 | std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernel( |
202 | std::unique_ptr<const fml::Mapping> kernel) { |
203 | return std::make_unique<KernelIsolateConfiguration>(std::move(kernel)); |
204 | } |
205 | |
206 | std::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 | |
217 | std::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 | |