// 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 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 kernel_; FML_DISALLOW_COPY_AND_ASSIGN(KernelIsolateConfiguration); }; class KernelListIsolateConfiguration final : public IsolateConfiguration { public: explicit KernelListIsolateConfiguration( std::vector>> 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>> kernel_piece_futures_; std::vector> resolved_kernel_pieces_; FML_DISALLOW_COPY_AND_ASSIGN(KernelListIsolateConfiguration); }; static std::vector ParseKernelListPaths( std::unique_ptr kernel_list) { FML_DCHECK(kernel_list); std::vector kernel_pieces_paths; const char* kernel_list_str = reinterpret_cast(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>> PrepareKernelMappings(const std::vector& kernel_pieces_paths, const std::shared_ptr& asset_manager, const fml::RefPtr& io_worker) { FML_DCHECK(asset_manager); std::vector>> fetch_futures; for (const auto& kernel_pieces_path : kernel_pieces_paths) { std::promise> 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::InferFromSettings( const Settings& settings, const std::shared_ptr& asset_manager, const fml::RefPtr& 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 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 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::CreateForAppSnapshot() { return std::make_unique(); } std::unique_ptr IsolateConfiguration::CreateForKernel( std::unique_ptr kernel) { return std::make_unique(std::move(kernel)); } std::unique_ptr IsolateConfiguration::CreateForKernelList( std::vector> kernel_pieces) { std::vector>> pieces; for (auto& piece : kernel_pieces) { if (!piece) { FML_DLOG(ERROR) << "Invalid kernel piece."; continue; } std::promise> promise; pieces.push_back(promise.get_future()); promise.set_value(std::move(piece)); } return CreateForKernelList(std::move(pieces)); } std::unique_ptr IsolateConfiguration::CreateForKernelList( std::vector>> kernel_pieces) { return std::make_unique( std::move(kernel_pieces)); } } // namespace flutter