blob: ffbc28e03549628207893d77888d94dab5996600 [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/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:
// The kernel mapping may be nullptr if reusing the group's loaded kernel.
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(const std::vector<std::string>& kernel_pieces_paths,
const std::shared_ptr<AssetManager>& asset_manager,
const 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,
const std::shared_ptr<AssetManager>& asset_manager,
const fml::RefPtr<fml::TaskRunner>& io_worker,
IsolateLaunchType launch_type) {
// Running in AOT mode.
if (DartVM::IsRunningPrecompiledCode()) {
return CreateForAppSnapshot();
}
if (launch_type == IsolateLaunchType::kExistingGroup) {
return CreateForKernel(nullptr);
}
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(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