// 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/shell/common/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(); } private: FML_DISALLOW_COPY_AND_ASSIGN(AppSnapshotIsolateConfiguration); }; class KernelIsolateConfiguration : public IsolateConfiguration { public: 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_)); } private: std::unique_ptr kernel_; FML_DISALLOW_COPY_AND_ASSIGN(KernelIsolateConfiguration); }; class KernelListIsolateConfiguration final : public IsolateConfiguration { public: KernelListIsolateConfiguration( std::vector>> kernel_pieces) : kernel_pieces_(std::move(kernel_pieces)) {} // |IsolateConfiguration| bool DoPrepareIsolate(DartIsolate& isolate) override { if (DartVM::IsRunningPrecompiledCode()) { return false; } for (size_t i = 0; i < kernel_pieces_.size(); i++) { bool last_piece = i + 1 == kernel_pieces_.size(); if (!isolate.PrepareForRunningFromKernel(kernel_pieces_[i].get(), last_piece)) { return false; } } return true; } private: std::vector>> 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(std::vector kernel_pieces_paths, std::shared_ptr asset_manager, 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, std::shared_ptr asset_manager, fml::RefPtr io_worker) { // Running in AOT mode. if (DartVM::IsRunningPrecompiledCode()) { return CreateForAppSnapshot(); } if (!asset_manager) { return 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; } // Running from kernel snapshot. { 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). { 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_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::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) { 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