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/dart_snapshot.h" |
6 | |
7 | #include <sstream> |
8 | |
9 | #include "flutter/fml/native_library.h" |
10 | #include "flutter/fml/paths.h" |
11 | #include "flutter/fml/trace_event.h" |
12 | #include "flutter/lib/snapshot/snapshot.h" |
13 | #include "flutter/runtime/dart_vm.h" |
14 | |
15 | namespace flutter { |
16 | |
17 | const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData" ; |
18 | const char* DartSnapshot::kVMInstructionsSymbol = "kDartVmSnapshotInstructions" ; |
19 | const char* DartSnapshot::kIsolateDataSymbol = "kDartIsolateSnapshotData" ; |
20 | const char* DartSnapshot::kIsolateInstructionsSymbol = |
21 | "kDartIsolateSnapshotInstructions" ; |
22 | |
23 | // On Windows and Android (in debug mode) the engine finds the Dart snapshot |
24 | // data through symbols that are statically linked into the executable. |
25 | // On other platforms this data is obtained by a dynamic symbol lookup. |
26 | #define DART_SNAPSHOT_STATIC_LINK \ |
27 | ((OS_WIN || OS_ANDROID) && FLUTTER_JIT_RUNTIME) |
28 | |
29 | #if !DART_SNAPSHOT_STATIC_LINK |
30 | |
31 | static std::unique_ptr<const fml::Mapping> GetFileMapping( |
32 | const std::string& path, |
33 | bool executable) { |
34 | if (executable) { |
35 | return fml::FileMapping::CreateReadExecute(path); |
36 | } else { |
37 | return fml::FileMapping::CreateReadOnly(path); |
38 | } |
39 | } |
40 | |
41 | // The first party embedders don't yet use the stable embedder API and depend on |
42 | // the engine figuring out the locations of the various heap and instructions |
43 | // buffers. Consequently, the engine had baked in opinions about where these |
44 | // buffers would reside and how they would be packaged (examples, in an external |
45 | // dylib, in the same dylib, at a path, at a path relative to and FD, etc..). As |
46 | // the needs of the platforms changed, the lack of an API meant that the engine |
47 | // had to be patched to look for new fields in the settings object. This grew |
48 | // untenable and with the addition of the new Fuchsia embedder and the generic C |
49 | // embedder API, embedders could specify the mapping directly. Once everyone |
50 | // moves to the embedder API, this method can effectively be reduced to just |
51 | // invoking the embedder_mapping_callback directly. |
52 | static std::shared_ptr<const fml::Mapping> SearchMapping( |
53 | MappingCallback embedder_mapping_callback, |
54 | const std::string& file_path, |
55 | const std::vector<std::string>& native_library_path, |
56 | const char* native_library_symbol_name, |
57 | bool is_executable) { |
58 | // Ask the embedder. There is no fallback as we expect the embedders (via |
59 | // their embedding APIs) to just specify the mappings directly. |
60 | if (embedder_mapping_callback) { |
61 | return embedder_mapping_callback(); |
62 | } |
63 | |
64 | // Attempt to open file at path specified. |
65 | if (file_path.size() > 0) { |
66 | if (auto file_mapping = GetFileMapping(file_path, is_executable)) { |
67 | return file_mapping; |
68 | } |
69 | } |
70 | |
71 | // Look in application specified native library if specified. |
72 | for (const std::string& path : native_library_path) { |
73 | auto native_library = fml::NativeLibrary::Create(path.c_str()); |
74 | auto symbol_mapping = std::make_unique<const fml::SymbolMapping>( |
75 | native_library, native_library_symbol_name); |
76 | if (symbol_mapping->GetMapping() != nullptr) { |
77 | return symbol_mapping; |
78 | } |
79 | } |
80 | |
81 | // Look inside the currently loaded process. |
82 | { |
83 | auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); |
84 | auto symbol_mapping = std::make_unique<const fml::SymbolMapping>( |
85 | loaded_process, native_library_symbol_name); |
86 | if (symbol_mapping->GetMapping() != nullptr) { |
87 | return symbol_mapping; |
88 | } |
89 | } |
90 | |
91 | return nullptr; |
92 | } |
93 | |
94 | #endif // !DART_SNAPSHOT_STATIC_LINK |
95 | |
96 | static std::shared_ptr<const fml::Mapping> ResolveVMData( |
97 | const Settings& settings) { |
98 | #if DART_SNAPSHOT_STATIC_LINK |
99 | return std::make_unique<fml::NonOwnedMapping>(kDartVmSnapshotData, 0); |
100 | #else // DART_SNAPSHOT_STATIC_LINK |
101 | return SearchMapping( |
102 | settings.vm_snapshot_data, // embedder_mapping_callback |
103 | settings.vm_snapshot_data_path, // file_path |
104 | settings.application_library_path, // native_library_path |
105 | DartSnapshot::kVMDataSymbol, // native_library_symbol_name |
106 | false // is_executable |
107 | ); |
108 | #endif // DART_SNAPSHOT_STATIC_LINK |
109 | } |
110 | |
111 | static std::shared_ptr<const fml::Mapping> ResolveVMInstructions( |
112 | const Settings& settings) { |
113 | #if DART_SNAPSHOT_STATIC_LINK |
114 | return std::make_unique<fml::NonOwnedMapping>(kDartVmSnapshotInstructions, 0); |
115 | #else // DART_SNAPSHOT_STATIC_LINK |
116 | return SearchMapping( |
117 | settings.vm_snapshot_instr, // embedder_mapping_callback |
118 | settings.vm_snapshot_instr_path, // file_path |
119 | settings.application_library_path, // native_library_path |
120 | DartSnapshot::kVMInstructionsSymbol, // native_library_symbol_name |
121 | true // is_executable |
122 | ); |
123 | #endif // DART_SNAPSHOT_STATIC_LINK |
124 | } |
125 | |
126 | static std::shared_ptr<const fml::Mapping> ResolveIsolateData( |
127 | const Settings& settings) { |
128 | #if DART_SNAPSHOT_STATIC_LINK |
129 | return std::make_unique<fml::NonOwnedMapping>(kDartIsolateSnapshotData, 0); |
130 | #else // DART_SNAPSHOT_STATIC_LINK |
131 | return SearchMapping( |
132 | settings.isolate_snapshot_data, // embedder_mapping_callback |
133 | settings.isolate_snapshot_data_path, // file_path |
134 | settings.application_library_path, // native_library_path |
135 | DartSnapshot::kIsolateDataSymbol, // native_library_symbol_name |
136 | false // is_executable |
137 | ); |
138 | #endif // DART_SNAPSHOT_STATIC_LINK |
139 | } |
140 | |
141 | static std::shared_ptr<const fml::Mapping> ResolveIsolateInstructions( |
142 | const Settings& settings) { |
143 | #if DART_SNAPSHOT_STATIC_LINK |
144 | return std::make_unique<fml::NonOwnedMapping>( |
145 | kDartIsolateSnapshotInstructions, 0); |
146 | #else // DART_SNAPSHOT_STATIC_LINK |
147 | return SearchMapping( |
148 | settings.isolate_snapshot_instr, // embedder_mapping_callback |
149 | settings.isolate_snapshot_instr_path, // file_path |
150 | settings.application_library_path, // native_library_path |
151 | DartSnapshot::kIsolateInstructionsSymbol, // native_library_symbol_name |
152 | true // is_executable |
153 | ); |
154 | #endif // DART_SNAPSHOT_STATIC_LINK |
155 | } |
156 | |
157 | fml::RefPtr<DartSnapshot> DartSnapshot::VMSnapshotFromSettings( |
158 | const Settings& settings) { |
159 | TRACE_EVENT0("flutter" , "DartSnapshot::VMSnapshotFromSettings" ); |
160 | auto snapshot = |
161 | fml::MakeRefCounted<DartSnapshot>(ResolveVMData(settings), // |
162 | ResolveVMInstructions(settings) // |
163 | ); |
164 | if (snapshot->IsValid()) { |
165 | return snapshot; |
166 | } |
167 | return nullptr; |
168 | } |
169 | |
170 | fml::RefPtr<DartSnapshot> DartSnapshot::IsolateSnapshotFromSettings( |
171 | const Settings& settings) { |
172 | TRACE_EVENT0("flutter" , "DartSnapshot::IsolateSnapshotFromSettings" ); |
173 | auto snapshot = |
174 | fml::MakeRefCounted<DartSnapshot>(ResolveIsolateData(settings), // |
175 | ResolveIsolateInstructions(settings) // |
176 | ); |
177 | if (snapshot->IsValid()) { |
178 | return snapshot; |
179 | } |
180 | return nullptr; |
181 | } |
182 | |
183 | DartSnapshot::DartSnapshot(std::shared_ptr<const fml::Mapping> data, |
184 | std::shared_ptr<const fml::Mapping> instructions) |
185 | : data_(std::move(data)), instructions_(std::move(instructions)) {} |
186 | |
187 | DartSnapshot::~DartSnapshot() = default; |
188 | |
189 | bool DartSnapshot::IsValid() const { |
190 | return static_cast<bool>(data_); |
191 | } |
192 | |
193 | bool DartSnapshot::IsValidForAOT() const { |
194 | return data_ && instructions_; |
195 | } |
196 | |
197 | const uint8_t* DartSnapshot::GetDataMapping() const { |
198 | return data_ ? data_->GetMapping() : nullptr; |
199 | } |
200 | |
201 | const uint8_t* DartSnapshot::GetInstructionsMapping() const { |
202 | return instructions_ ? instructions_->GetMapping() : nullptr; |
203 | } |
204 | |
205 | } // namespace flutter |
206 | |