// 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 #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 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 SearchMapping( const MappingCallback& embedder_mapping_callback, const std::string& file_path, const std::vector& 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( 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( 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 ResolveVMData( const Settings& settings) { #if DART_SNAPSHOT_STATIC_LINK return std::make_unique(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 ResolveVMInstructions( const Settings& settings) { #if DART_SNAPSHOT_STATIC_LINK return std::make_unique(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 ResolveIsolateData( const Settings& settings) { #if DART_SNAPSHOT_STATIC_LINK return std::make_unique(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 ResolveIsolateInstructions( const Settings& settings) { #if DART_SNAPSHOT_STATIC_LINK return std::make_unique( 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 DartSnapshot::VMSnapshotFromSettings( const Settings& settings) { TRACE_EVENT0("flutter", "DartSnapshot::VMSnapshotFromSettings"); auto snapshot = fml::MakeRefCounted(ResolveVMData(settings), // ResolveVMInstructions(settings) // ); if (snapshot->IsValid()) { return snapshot; } return nullptr; } fml::RefPtr DartSnapshot::IsolateSnapshotFromSettings( const Settings& settings) { TRACE_EVENT0("flutter", "DartSnapshot::IsolateSnapshotFromSettings"); auto snapshot = fml::MakeRefCounted(ResolveIsolateData(settings), // ResolveIsolateInstructions(settings) // ); if (snapshot->IsValid()) { return snapshot; } return nullptr; } fml::RefPtr DartSnapshot::IsolateSnapshotFromMappings( const std::shared_ptr& snapshot_data, const std::shared_ptr& snapshot_instructions) { auto snapshot = fml::MakeRefCounted(snapshot_data, snapshot_instructions); if (snapshot->IsValid()) { return snapshot; } return nullptr; } fml::RefPtr 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 snapshot_data = SearchMapping(nullptr, "", settings.vmservice_snapshot_library_path, DartSnapshot::kIsolateDataSymbol, false); std::shared_ptr 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 data, std::shared_ptr instructions) : data_(std::move(data)), instructions_(std::move(instructions)) {} DartSnapshot::~DartSnapshot() = default; bool DartSnapshot::IsValid() const { return static_cast(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