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
15namespace flutter {
16
17const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData";
18const char* DartSnapshot::kVMInstructionsSymbol = "kDartVmSnapshotInstructions";
19const char* DartSnapshot::kIsolateDataSymbol = "kDartIsolateSnapshotData";
20const 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
31static 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.
52static 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
96static 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
111static 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
126static 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
141static 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
157fml::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
170fml::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
183DartSnapshot::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
187DartSnapshot::~DartSnapshot() = default;
188
189bool DartSnapshot::IsValid() const {
190 return static_cast<bool>(data_);
191}
192
193bool DartSnapshot::IsValidForAOT() const {
194 return data_ && instructions_;
195}
196
197const uint8_t* DartSnapshot::GetDataMapping() const {
198 return data_ ? data_->GetMapping() : nullptr;
199}
200
201const uint8_t* DartSnapshot::GetInstructionsMapping() const {
202 return instructions_ ? instructions_->GetMapping() : nullptr;
203}
204
205} // namespace flutter
206