mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
295 lines
9.5 KiB
C++
295 lines
9.5 KiB
C++
// 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/isolate_configuration.h"
|
|
|
|
#include "flutter/fml/make_copyable.h"
|
|
#include "flutter/runtime/dart_vm.h"
|
|
|
|
namespace flutter {
|
|
|
|
IsolateConfiguration::IsolateConfiguration() = default;
|
|
|
|
IsolateConfiguration::~IsolateConfiguration() = default;
|
|
|
|
bool IsolateConfiguration::PrepareIsolate(DartIsolate& isolate) {
|
|
if (isolate.GetPhase() != DartIsolate::Phase::LibrariesSetup) {
|
|
FML_DLOG(ERROR)
|
|
<< "Isolate was in incorrect phase to be prepared for running.";
|
|
return false;
|
|
}
|
|
|
|
return DoPrepareIsolate(isolate);
|
|
}
|
|
|
|
class AppSnapshotIsolateConfiguration final : public IsolateConfiguration {
|
|
public:
|
|
AppSnapshotIsolateConfiguration() = default;
|
|
|
|
// |IsolateConfiguration|
|
|
bool DoPrepareIsolate(DartIsolate& isolate) override {
|
|
return isolate.PrepareForRunningFromPrecompiledCode();
|
|
}
|
|
|
|
// |IsolateConfiguration|
|
|
bool IsNullSafetyEnabled(const DartSnapshot& snapshot) override {
|
|
return snapshot.IsNullSafetyEnabled(nullptr);
|
|
}
|
|
|
|
private:
|
|
FML_DISALLOW_COPY_AND_ASSIGN(AppSnapshotIsolateConfiguration);
|
|
};
|
|
|
|
class KernelIsolateConfiguration : public IsolateConfiguration {
|
|
public:
|
|
explicit KernelIsolateConfiguration(
|
|
std::unique_ptr<const fml::Mapping> kernel)
|
|
: kernel_(std::move(kernel)) {}
|
|
|
|
// |IsolateConfiguration|
|
|
bool DoPrepareIsolate(DartIsolate& isolate) override {
|
|
if (DartVM::IsRunningPrecompiledCode()) {
|
|
return false;
|
|
}
|
|
return isolate.PrepareForRunningFromKernel(std::move(kernel_),
|
|
/*child_isolate=*/false,
|
|
/*last_piece=*/true);
|
|
}
|
|
|
|
// |IsolateConfiguration|
|
|
bool IsNullSafetyEnabled(const DartSnapshot& snapshot) override {
|
|
return snapshot.IsNullSafetyEnabled(kernel_.get());
|
|
}
|
|
|
|
private:
|
|
std::unique_ptr<const fml::Mapping> kernel_;
|
|
|
|
FML_DISALLOW_COPY_AND_ASSIGN(KernelIsolateConfiguration);
|
|
};
|
|
|
|
class KernelListIsolateConfiguration final : public IsolateConfiguration {
|
|
public:
|
|
explicit KernelListIsolateConfiguration(
|
|
std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
|
|
kernel_pieces)
|
|
: kernel_piece_futures_(std::move(kernel_pieces)) {
|
|
if (kernel_piece_futures_.empty()) {
|
|
FML_LOG(ERROR) << "Attempted to create kernel list configuration without "
|
|
"any kernel blobs.";
|
|
}
|
|
}
|
|
|
|
// |IsolateConfiguration|
|
|
bool DoPrepareIsolate(DartIsolate& isolate) override {
|
|
if (DartVM::IsRunningPrecompiledCode()) {
|
|
return false;
|
|
}
|
|
|
|
ResolveKernelPiecesIfNecessary();
|
|
|
|
if (resolved_kernel_pieces_.empty()) {
|
|
FML_DLOG(ERROR) << "No kernel pieces provided to prepare this isolate.";
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < resolved_kernel_pieces_.size(); i++) {
|
|
if (!resolved_kernel_pieces_[i]) {
|
|
FML_DLOG(ERROR) << "This kernel list isolate configuration was already "
|
|
"used to prepare an isolate.";
|
|
return false;
|
|
}
|
|
const bool last_piece = i + 1 == resolved_kernel_pieces_.size();
|
|
if (!isolate.PrepareForRunningFromKernel(
|
|
std::move(resolved_kernel_pieces_[i]), /*child_isolate=*/false,
|
|
last_piece)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// |IsolateConfiguration|
|
|
bool IsNullSafetyEnabled(const DartSnapshot& snapshot) override {
|
|
ResolveKernelPiecesIfNecessary();
|
|
const auto kernel = resolved_kernel_pieces_.empty()
|
|
? nullptr
|
|
: resolved_kernel_pieces_.front().get();
|
|
return snapshot.IsNullSafetyEnabled(kernel);
|
|
}
|
|
|
|
// This must be call as late as possible before accessing any of the kernel
|
|
// pieces. This will delay blocking on the futures for as long as possible. So
|
|
// far, only Fuchsia depends on this optimization and only on the non-AOT
|
|
// configs.
|
|
void ResolveKernelPiecesIfNecessary() {
|
|
if (resolved_kernel_pieces_.size() == kernel_piece_futures_.size()) {
|
|
return;
|
|
}
|
|
|
|
resolved_kernel_pieces_.clear();
|
|
for (auto& piece : kernel_piece_futures_) {
|
|
// The get() call will xfer the unique pointer out and leave an empty
|
|
// future in the original vector.
|
|
resolved_kernel_pieces_.emplace_back(piece.get());
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
|
|
kernel_piece_futures_;
|
|
std::vector<std::unique_ptr<const fml::Mapping>> resolved_kernel_pieces_;
|
|
|
|
FML_DISALLOW_COPY_AND_ASSIGN(KernelListIsolateConfiguration);
|
|
};
|
|
|
|
static std::vector<std::string> ParseKernelListPaths(
|
|
std::unique_ptr<fml::Mapping> kernel_list) {
|
|
FML_DCHECK(kernel_list);
|
|
|
|
std::vector<std::string> kernel_pieces_paths;
|
|
|
|
const char* kernel_list_str =
|
|
reinterpret_cast<const char*>(kernel_list->GetMapping());
|
|
size_t kernel_list_size = kernel_list->GetSize();
|
|
|
|
size_t piece_path_start = 0;
|
|
while (piece_path_start < kernel_list_size) {
|
|
size_t piece_path_end = piece_path_start;
|
|
while ((piece_path_end < kernel_list_size) &&
|
|
(kernel_list_str[piece_path_end] != '\n')) {
|
|
piece_path_end++;
|
|
}
|
|
std::string piece_path(&kernel_list_str[piece_path_start],
|
|
piece_path_end - piece_path_start);
|
|
kernel_pieces_paths.emplace_back(std::move(piece_path));
|
|
|
|
piece_path_start = piece_path_end + 1;
|
|
}
|
|
|
|
return kernel_pieces_paths;
|
|
}
|
|
|
|
static std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
|
|
PrepareKernelMappings(std::vector<std::string> kernel_pieces_paths,
|
|
std::shared_ptr<AssetManager> asset_manager,
|
|
fml::RefPtr<fml::TaskRunner> io_worker) {
|
|
FML_DCHECK(asset_manager);
|
|
std::vector<std::future<std::unique_ptr<const fml::Mapping>>> fetch_futures;
|
|
|
|
for (const auto& kernel_pieces_path : kernel_pieces_paths) {
|
|
std::promise<std::unique_ptr<const fml::Mapping>> fetch_promise;
|
|
fetch_futures.push_back(fetch_promise.get_future());
|
|
auto fetch_task =
|
|
fml::MakeCopyable([asset_manager, kernel_pieces_path,
|
|
fetch_promise = std::move(fetch_promise)]() mutable {
|
|
fetch_promise.set_value(
|
|
asset_manager->GetAsMapping(kernel_pieces_path));
|
|
});
|
|
// Fulfill the promise on the worker if one is available or the current
|
|
// thread if one is not.
|
|
if (io_worker) {
|
|
io_worker->PostTask(fetch_task);
|
|
} else {
|
|
fetch_task();
|
|
}
|
|
}
|
|
|
|
return fetch_futures;
|
|
}
|
|
|
|
std::unique_ptr<IsolateConfiguration> IsolateConfiguration::InferFromSettings(
|
|
const Settings& settings,
|
|
std::shared_ptr<AssetManager> asset_manager,
|
|
fml::RefPtr<fml::TaskRunner> io_worker) {
|
|
// Running in AOT mode.
|
|
if (DartVM::IsRunningPrecompiledCode()) {
|
|
return CreateForAppSnapshot();
|
|
}
|
|
|
|
if (settings.application_kernels) {
|
|
return CreateForKernelList(settings.application_kernels());
|
|
}
|
|
|
|
if (settings.application_kernel_asset.empty() &&
|
|
settings.application_kernel_list_asset.empty()) {
|
|
FML_DLOG(ERROR) << "application_kernel_asset or "
|
|
"application_kernel_list_asset must be set";
|
|
return nullptr;
|
|
}
|
|
|
|
if (!asset_manager) {
|
|
FML_DLOG(ERROR) << "No asset manager specified when attempting to create "
|
|
"isolate configuration.";
|
|
return nullptr;
|
|
}
|
|
|
|
// Running from kernel snapshot. Requires asset manager.
|
|
{
|
|
std::unique_ptr<fml::Mapping> kernel =
|
|
asset_manager->GetAsMapping(settings.application_kernel_asset);
|
|
if (kernel) {
|
|
return CreateForKernel(std::move(kernel));
|
|
}
|
|
}
|
|
|
|
// Running from kernel divided into several pieces (for sharing). Requires
|
|
// asset manager and io worker.
|
|
|
|
if (!io_worker) {
|
|
FML_DLOG(ERROR) << "No IO worker specified to load kernel pieces.";
|
|
return nullptr;
|
|
}
|
|
|
|
{
|
|
std::unique_ptr<fml::Mapping> kernel_list =
|
|
asset_manager->GetAsMapping(settings.application_kernel_list_asset);
|
|
if (!kernel_list) {
|
|
FML_LOG(ERROR) << "Failed to load: "
|
|
<< settings.application_kernel_list_asset;
|
|
return nullptr;
|
|
}
|
|
auto kernel_pieces_paths = ParseKernelListPaths(std::move(kernel_list));
|
|
auto kernel_mappings = PrepareKernelMappings(std::move(kernel_pieces_paths),
|
|
asset_manager, io_worker);
|
|
return CreateForKernelList(std::move(kernel_mappings));
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<IsolateConfiguration>
|
|
IsolateConfiguration::CreateForAppSnapshot() {
|
|
return std::make_unique<AppSnapshotIsolateConfiguration>();
|
|
}
|
|
|
|
std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernel(
|
|
std::unique_ptr<const fml::Mapping> kernel) {
|
|
return std::make_unique<KernelIsolateConfiguration>(std::move(kernel));
|
|
}
|
|
|
|
std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernelList(
|
|
std::vector<std::unique_ptr<const fml::Mapping>> kernel_pieces) {
|
|
std::vector<std::future<std::unique_ptr<const fml::Mapping>>> pieces;
|
|
for (auto& piece : kernel_pieces) {
|
|
if (!piece) {
|
|
FML_DLOG(ERROR) << "Invalid kernel piece.";
|
|
continue;
|
|
}
|
|
std::promise<std::unique_ptr<const fml::Mapping>> promise;
|
|
pieces.push_back(promise.get_future());
|
|
promise.set_value(std::move(piece));
|
|
}
|
|
return CreateForKernelList(std::move(pieces));
|
|
}
|
|
|
|
std::unique_ptr<IsolateConfiguration> IsolateConfiguration::CreateForKernelList(
|
|
std::vector<std::future<std::unique_ptr<const fml::Mapping>>>
|
|
kernel_pieces) {
|
|
return std::make_unique<KernelListIsolateConfiguration>(
|
|
std::move(kernel_pieces));
|
|
}
|
|
|
|
} // namespace flutter
|