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_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG))
28
29 #if !DART_SNAPSHOT_STATIC_LINK
30
GetFileMapping(const std::string & path,bool executable)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.
SearchMapping(MappingCallback embedder_mapping_callback,const std::string & file_path,const std::vector<std::string> & native_library_path,const char * native_library_symbol_name,bool is_executable)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
ResolveVMData(const Settings & settings)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
ResolveVMInstructions(const Settings & settings)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
ResolveIsolateData(const Settings & settings)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
ResolveIsolateInstructions(const Settings & settings)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
VMSnapshotFromSettings(const Settings & settings)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
IsolateSnapshotFromSettings(const Settings & settings)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
Empty()183 fml::RefPtr<DartSnapshot> DartSnapshot::Empty() {
184 return fml::MakeRefCounted<DartSnapshot>(nullptr, nullptr);
185 }
186
DartSnapshot(std::shared_ptr<const fml::Mapping> data,std::shared_ptr<const fml::Mapping> instructions)187 DartSnapshot::DartSnapshot(std::shared_ptr<const fml::Mapping> data,
188 std::shared_ptr<const fml::Mapping> instructions)
189 : data_(std::move(data)), instructions_(std::move(instructions)) {}
190
191 DartSnapshot::~DartSnapshot() = default;
192
IsValid() const193 bool DartSnapshot::IsValid() const {
194 return static_cast<bool>(data_);
195 }
196
IsValidForAOT() const197 bool DartSnapshot::IsValidForAOT() const {
198 return data_ && instructions_;
199 }
200
GetDataMapping() const201 const uint8_t* DartSnapshot::GetDataMapping() const {
202 return data_ ? data_->GetMapping() : nullptr;
203 }
204
GetInstructionsMapping() const205 const uint8_t* DartSnapshot::GetInstructionsMapping() const {
206 return instructions_ ? instructions_->GetMapping() : nullptr;
207 }
208
209 } // namespace flutter
210