blob: 5943524aa9f8066ae8738b028f1c42c595bb6200 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/runtime/dart_snapshot.h"
#include <sstream>
#include "flutter/fml/native_library.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/trace_event.h"
#include "flutter/lib/snapshot/snapshot.h"
#include "flutter/runtime/dart_vm.h"
#include "third_party/dart/runtime/include/dart_api.h"
namespace flutter {
const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData";
const char* DartSnapshot::kVMInstructionsSymbol = "kDartVmSnapshotInstructions";
const char* DartSnapshot::kIsolateDataSymbol = "kDartIsolateSnapshotData";
const char* DartSnapshot::kIsolateInstructionsSymbol =
"kDartIsolateSnapshotInstructions";
// On Windows and Android (in debug mode) the engine finds the Dart snapshot
// data through symbols that are statically linked into the executable.
// On other platforms this data is obtained by a dynamic symbol lookup.
#define DART_SNAPSHOT_STATIC_LINK \
((FML_OS_WIN || FML_OS_ANDROID) && FLUTTER_JIT_RUNTIME)
#if !DART_SNAPSHOT_STATIC_LINK
static std::unique_ptr<const fml::Mapping> GetFileMapping(
const std::string& path,
bool executable) {
if (executable) {
return fml::FileMapping::CreateReadExecute(path);
} else {
return fml::FileMapping::CreateReadOnly(path);
}
}
// The first party embedders don't yet use the stable embedder API and depend on
// the engine figuring out the locations of the various heap and instructions
// buffers. Consequently, the engine had baked in opinions about where these
// buffers would reside and how they would be packaged (examples, in an external
// dylib, in the same dylib, at a path, at a path relative to and FD, etc..). As
// the needs of the platforms changed, the lack of an API meant that the engine
// had to be patched to look for new fields in the settings object. This grew
// untenable and with the addition of the new Fuchsia embedder and the generic C
// embedder API, embedders could specify the mapping directly. Once everyone
// moves to the embedder API, this method can effectively be reduced to just
// invoking the embedder_mapping_callback directly.
static std::shared_ptr<const fml::Mapping> SearchMapping(
const 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) {
// Ask the embedder. There is no fallback as we expect the embedders (via
// their embedding APIs) to just specify the mappings directly.
if (embedder_mapping_callback) {
// Note that mapping will be nullptr if the mapping callback returns an
// invalid mapping. If all the other methods for resolving the data also
// fail, the engine will stop with accompanying error logs.
if (auto mapping = embedder_mapping_callback()) {
return mapping;
}
}
// Attempt to open file at path specified.
if (!file_path.empty()) {
if (auto file_mapping = GetFileMapping(file_path, is_executable)) {
return file_mapping;
}
}
// Look in application specified native library if specified.
for (const std::string& path : native_library_path) {
auto native_library = fml::NativeLibrary::Create(path.c_str());
auto symbol_mapping = std::make_unique<const fml::SymbolMapping>(
native_library, native_library_symbol_name);
if (symbol_mapping->GetMapping() != nullptr) {
return symbol_mapping;
}
}
// Look inside the currently loaded process.
{
auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess();
auto symbol_mapping = std::make_unique<const fml::SymbolMapping>(
loaded_process, native_library_symbol_name);
if (symbol_mapping->GetMapping() != nullptr) {
return symbol_mapping;
}
}
return nullptr;
}
#endif // !DART_SNAPSHOT_STATIC_LINK
static std::shared_ptr<const fml::Mapping> ResolveVMData(
const Settings& settings) {
#if DART_SNAPSHOT_STATIC_LINK
return std::make_unique<fml::NonOwnedMapping>(kDartVmSnapshotData,
0, // size
nullptr, // release_func
true // dontneed_safe
);
#else // DART_SNAPSHOT_STATIC_LINK
return SearchMapping(
settings.vm_snapshot_data, // embedder_mapping_callback
settings.vm_snapshot_data_path, // file_path
settings.application_library_path, // native_library_path
DartSnapshot::kVMDataSymbol, // native_library_symbol_name
false // is_executable
);
#endif // DART_SNAPSHOT_STATIC_LINK
}
static std::shared_ptr<const fml::Mapping> ResolveVMInstructions(
const Settings& settings) {
#if DART_SNAPSHOT_STATIC_LINK
return std::make_unique<fml::NonOwnedMapping>(kDartVmSnapshotInstructions,
0, // size
nullptr, // release_func
true // dontneed_safe
);
#else // DART_SNAPSHOT_STATIC_LINK
return SearchMapping(
settings.vm_snapshot_instr, // embedder_mapping_callback
settings.vm_snapshot_instr_path, // file_path
settings.application_library_path, // native_library_path
DartSnapshot::kVMInstructionsSymbol, // native_library_symbol_name
true // is_executable
);
#endif // DART_SNAPSHOT_STATIC_LINK
}
static std::shared_ptr<const fml::Mapping> ResolveIsolateData(
const Settings& settings) {
#if DART_SNAPSHOT_STATIC_LINK
return std::make_unique<fml::NonOwnedMapping>(kDartIsolateSnapshotData,
0, // size
nullptr, // release_func
true // dontneed_safe
);
#else // DART_SNAPSHOT_STATIC_LINK
return SearchMapping(
settings.isolate_snapshot_data, // embedder_mapping_callback
settings.isolate_snapshot_data_path, // file_path
settings.application_library_path, // native_library_path
DartSnapshot::kIsolateDataSymbol, // native_library_symbol_name
false // is_executable
);
#endif // DART_SNAPSHOT_STATIC_LINK
}
static std::shared_ptr<const fml::Mapping> ResolveIsolateInstructions(
const Settings& settings) {
#if DART_SNAPSHOT_STATIC_LINK
return std::make_unique<fml::NonOwnedMapping>(
kDartIsolateSnapshotInstructions,
0, // size
nullptr, // release_func
true // dontneed_safe
);
#else // DART_SNAPSHOT_STATIC_LINK
return SearchMapping(
settings.isolate_snapshot_instr, // embedder_mapping_callback
settings.isolate_snapshot_instr_path, // file_path
settings.application_library_path, // native_library_path
DartSnapshot::kIsolateInstructionsSymbol, // native_library_symbol_name
true // is_executable
);
#endif // DART_SNAPSHOT_STATIC_LINK
}
fml::RefPtr<const DartSnapshot> DartSnapshot::VMSnapshotFromSettings(
const Settings& settings) {
TRACE_EVENT0("flutter", "DartSnapshot::VMSnapshotFromSettings");
auto snapshot =
fml::MakeRefCounted<DartSnapshot>(ResolveVMData(settings), //
ResolveVMInstructions(settings) //
);
if (snapshot->IsValid()) {
return snapshot;
}
return nullptr;
}
fml::RefPtr<const DartSnapshot> DartSnapshot::IsolateSnapshotFromSettings(
const Settings& settings) {
TRACE_EVENT0("flutter", "DartSnapshot::IsolateSnapshotFromSettings");
auto snapshot =
fml::MakeRefCounted<DartSnapshot>(ResolveIsolateData(settings), //
ResolveIsolateInstructions(settings) //
);
if (snapshot->IsValid()) {
return snapshot;
}
return nullptr;
}
fml::RefPtr<DartSnapshot> DartSnapshot::IsolateSnapshotFromMappings(
const std::shared_ptr<const fml::Mapping>& snapshot_data,
const std::shared_ptr<const fml::Mapping>& snapshot_instructions) {
auto snapshot =
fml::MakeRefCounted<DartSnapshot>(snapshot_data, snapshot_instructions);
if (snapshot->IsValid()) {
return snapshot;
}
return nullptr;
}
fml::RefPtr<DartSnapshot> DartSnapshot::VMServiceIsolateSnapshotFromSettings(
const Settings& settings) {
#if DART_SNAPSHOT_STATIC_LINK
return nullptr;
#else // DART_SNAPSHOT_STATIC_LINK
if (settings.vmservice_snapshot_library_path.empty()) {
return nullptr;
}
std::shared_ptr<const fml::Mapping> snapshot_data =
SearchMapping(nullptr, "", settings.vmservice_snapshot_library_path,
DartSnapshot::kIsolateDataSymbol, false);
std::shared_ptr<const fml::Mapping> snapshot_instructions =
SearchMapping(nullptr, "", settings.vmservice_snapshot_library_path,
DartSnapshot::kIsolateInstructionsSymbol, true);
return IsolateSnapshotFromMappings(snapshot_data, snapshot_instructions);
#endif // DART_SNAPSHOT_STATIC_LINK
}
DartSnapshot::DartSnapshot(std::shared_ptr<const fml::Mapping> data,
std::shared_ptr<const fml::Mapping> instructions)
: data_(std::move(data)), instructions_(std::move(instructions)) {}
DartSnapshot::~DartSnapshot() = default;
bool DartSnapshot::IsValid() const {
return static_cast<bool>(data_);
}
bool DartSnapshot::IsValidForAOT() const {
return data_ && instructions_;
}
const uint8_t* DartSnapshot::GetDataMapping() const {
return data_ ? data_->GetMapping() : nullptr;
}
const uint8_t* DartSnapshot::GetInstructionsMapping() const {
return instructions_ ? instructions_->GetMapping() : nullptr;
}
bool DartSnapshot::IsDontNeedSafe() const {
if (data_ && !data_->IsDontNeedSafe()) {
return false;
}
if (instructions_ && !instructions_->IsDontNeedSafe()) {
return false;
}
return true;
}
bool DartSnapshot::IsNullSafetyEnabled(const fml::Mapping* kernel) const {
return ::Dart_DetectNullSafety(
nullptr, // script_uri (unsupported by Flutter)
nullptr, // package_config (package resolution of parent used)
nullptr, // original_working_directory (no package config)
GetDataMapping(), // snapshot_data
GetInstructionsMapping(), // snapshot_instructions
kernel ? kernel->GetMapping() : nullptr, // kernel_buffer
kernel ? kernel->GetSize() : 0u // kernel_buffer_size
);
}
} // namespace flutter