mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Group together externally-managed UIDartState. It's a frequent pattern to enable access to shell resources from the framework via UIDartState. These handles are passed through several other objects, where they lay mostly dormant. This refactor just aims to ease maintenance of this state. UIDartState is essentially just an easy to extend bus for dropping off the shell kids in UIDartState, with constructors/operators that remove the need for providing a full initializer lists in unittests.
603 lines
20 KiB
C++
603 lines
20 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/shell/common/engine.h"
|
|
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "flutter/common/settings.h"
|
|
#include "flutter/fml/eintr_wrapper.h"
|
|
#include "flutter/fml/file.h"
|
|
#include "flutter/fml/make_copyable.h"
|
|
#include "flutter/fml/paths.h"
|
|
#include "flutter/fml/trace_event.h"
|
|
#include "flutter/fml/unique_fd.h"
|
|
#include "flutter/lib/snapshot/snapshot.h"
|
|
#include "flutter/lib/ui/text/font_collection.h"
|
|
#include "flutter/shell/common/animator.h"
|
|
#include "flutter/shell/common/platform_view.h"
|
|
#include "flutter/shell/common/shell.h"
|
|
#include "rapidjson/document.h"
|
|
#include "third_party/dart/runtime/include/dart_tools_api.h"
|
|
#include "third_party/skia/include/core/SkCanvas.h"
|
|
#include "third_party/skia/include/core/SkPictureRecorder.h"
|
|
|
|
namespace flutter {
|
|
|
|
static constexpr char kAssetChannel[] = "flutter/assets";
|
|
static constexpr char kLifecycleChannel[] = "flutter/lifecycle";
|
|
static constexpr char kNavigationChannel[] = "flutter/navigation";
|
|
static constexpr char kLocalizationChannel[] = "flutter/localization";
|
|
static constexpr char kSettingsChannel[] = "flutter/settings";
|
|
static constexpr char kIsolateChannel[] = "flutter/isolate";
|
|
|
|
namespace {
|
|
fml::MallocMapping MakeMapping(const std::string& str) {
|
|
return fml::MallocMapping::Copy(str.c_str(), str.length());
|
|
}
|
|
} // namespace
|
|
|
|
Engine::Engine(
|
|
Delegate& delegate,
|
|
const PointerDataDispatcherMaker& dispatcher_maker,
|
|
std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
|
|
TaskRunners task_runners,
|
|
Settings settings,
|
|
std::unique_ptr<Animator> animator,
|
|
fml::WeakPtr<IOManager> io_manager,
|
|
const std::shared_ptr<FontCollection>& font_collection,
|
|
std::unique_ptr<RuntimeController> runtime_controller)
|
|
: delegate_(delegate),
|
|
settings_(std::move(settings)),
|
|
animator_(std::move(animator)),
|
|
runtime_controller_(std::move(runtime_controller)),
|
|
activity_running_(true),
|
|
have_surface_(false),
|
|
font_collection_(font_collection),
|
|
image_decoder_(task_runners, image_decoder_task_runner, io_manager),
|
|
task_runners_(std::move(task_runners)),
|
|
weak_factory_(this) {
|
|
pointer_data_dispatcher_ = dispatcher_maker(*this);
|
|
}
|
|
|
|
Engine::Engine(Delegate& delegate,
|
|
const PointerDataDispatcherMaker& dispatcher_maker,
|
|
DartVM& vm,
|
|
fml::RefPtr<const DartSnapshot> isolate_snapshot,
|
|
TaskRunners task_runners,
|
|
const PlatformData& platform_data,
|
|
Settings settings,
|
|
std::unique_ptr<Animator> animator,
|
|
fml::WeakPtr<IOManager> io_manager,
|
|
fml::RefPtr<SkiaUnrefQueue> unref_queue,
|
|
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
|
std::shared_ptr<VolatilePathTracker> volatile_path_tracker)
|
|
: Engine(delegate,
|
|
dispatcher_maker,
|
|
vm.GetConcurrentWorkerTaskRunner(),
|
|
task_runners,
|
|
settings,
|
|
std::move(animator),
|
|
io_manager,
|
|
std::make_shared<FontCollection>(),
|
|
nullptr) {
|
|
runtime_controller_ = std::make_unique<RuntimeController>(
|
|
*this, // runtime delegate
|
|
&vm, // VM
|
|
std::move(isolate_snapshot), // isolate snapshot
|
|
settings_.idle_notification_callback, // idle notification callback
|
|
platform_data, // platform data
|
|
settings_.isolate_create_callback, // isolate create callback
|
|
settings_.isolate_shutdown_callback, // isolate shutdown callback
|
|
settings_.persistent_isolate_data, // persistent isolate data
|
|
UIDartState::Context{
|
|
task_runners_, // task runners
|
|
std::move(snapshot_delegate), // snapshot delegate
|
|
GetWeakPtr(), // hint freed delegate
|
|
std::move(io_manager), // io manager
|
|
std::move(unref_queue), // Skia unref queue
|
|
image_decoder_.GetWeakPtr(), // image decoder
|
|
image_generator_registry_.GetWeakPtr(), // image generator registry
|
|
settings_.advisory_script_uri, // advisory script uri
|
|
settings_.advisory_script_entrypoint, // advisory script entrypoint
|
|
std::move(volatile_path_tracker), // volatile path tracker
|
|
});
|
|
}
|
|
|
|
std::unique_ptr<Engine> Engine::Spawn(
|
|
Delegate& delegate,
|
|
const PointerDataDispatcherMaker& dispatcher_maker,
|
|
Settings settings,
|
|
std::unique_ptr<Animator> animator) const {
|
|
auto result = std::make_unique<Engine>(
|
|
/*delegate=*/delegate,
|
|
/*dispatcher_maker=*/dispatcher_maker,
|
|
/*image_decoder_task_runner=*/
|
|
runtime_controller_->GetDartVM()->GetConcurrentWorkerTaskRunner(),
|
|
/*task_runners=*/task_runners_,
|
|
/*settings=*/settings,
|
|
/*animator=*/std::move(animator),
|
|
/*io_manager=*/runtime_controller_->GetIOManager(),
|
|
/*font_collection=*/font_collection_,
|
|
/*runtime_controller=*/nullptr);
|
|
result->runtime_controller_ = runtime_controller_->Spawn(
|
|
*result, // runtime delegate
|
|
settings_.advisory_script_uri, // advisory script uri
|
|
settings_.advisory_script_entrypoint, // advisory script entrypoint
|
|
settings_.idle_notification_callback, // idle notification callback
|
|
settings_.isolate_create_callback, // isolate create callback
|
|
settings_.isolate_shutdown_callback, // isolate shutdown callback
|
|
settings_.persistent_isolate_data // persistent isolate data
|
|
);
|
|
return result;
|
|
}
|
|
|
|
Engine::~Engine() = default;
|
|
|
|
fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
|
|
return weak_factory_.GetWeakPtr();
|
|
}
|
|
|
|
void Engine::SetupDefaultFontManager() {
|
|
TRACE_EVENT0("flutter", "Engine::SetupDefaultFontManager");
|
|
font_collection_->SetupDefaultFontManager();
|
|
}
|
|
|
|
std::shared_ptr<AssetManager> Engine::GetAssetManager() {
|
|
return asset_manager_;
|
|
}
|
|
|
|
bool Engine::UpdateAssetManager(
|
|
std::shared_ptr<AssetManager> new_asset_manager) {
|
|
if (asset_manager_ == new_asset_manager) {
|
|
return false;
|
|
}
|
|
|
|
asset_manager_ = new_asset_manager;
|
|
|
|
if (!asset_manager_) {
|
|
return false;
|
|
}
|
|
|
|
// Using libTXT as the text engine.
|
|
font_collection_->RegisterFonts(asset_manager_);
|
|
|
|
if (settings_.use_test_fonts) {
|
|
font_collection_->RegisterTestFonts();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Engine::Restart(RunConfiguration configuration) {
|
|
TRACE_EVENT0("flutter", "Engine::Restart");
|
|
if (!configuration.IsValid()) {
|
|
FML_LOG(ERROR) << "Engine run configuration was invalid.";
|
|
return false;
|
|
}
|
|
delegate_.OnPreEngineRestart();
|
|
runtime_controller_ = runtime_controller_->Clone();
|
|
UpdateAssetManager(nullptr);
|
|
return Run(std::move(configuration)) == Engine::RunStatus::Success;
|
|
}
|
|
|
|
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
|
|
if (!configuration.IsValid()) {
|
|
FML_LOG(ERROR) << "Engine run configuration was invalid.";
|
|
return RunStatus::Failure;
|
|
}
|
|
|
|
last_entry_point_ = configuration.GetEntrypoint();
|
|
last_entry_point_library_ = configuration.GetEntrypointLibrary();
|
|
|
|
UpdateAssetManager(configuration.GetAssetManager());
|
|
|
|
if (runtime_controller_->IsRootIsolateRunning()) {
|
|
return RunStatus::FailureAlreadyRunning;
|
|
}
|
|
|
|
if (!runtime_controller_->LaunchRootIsolate(
|
|
settings_, //
|
|
configuration.GetEntrypoint(), //
|
|
configuration.GetEntrypointLibrary(), //
|
|
configuration.TakeIsolateConfiguration()) //
|
|
) {
|
|
return RunStatus::Failure;
|
|
}
|
|
|
|
auto service_id = runtime_controller_->GetRootIsolateServiceID();
|
|
if (service_id.has_value()) {
|
|
std::unique_ptr<PlatformMessage> service_id_message =
|
|
std::make_unique<flutter::PlatformMessage>(
|
|
kIsolateChannel, MakeMapping(service_id.value()), nullptr);
|
|
HandlePlatformMessage(std::move(service_id_message));
|
|
}
|
|
|
|
return Engine::RunStatus::Success;
|
|
}
|
|
|
|
void Engine::BeginFrame(fml::TimePoint frame_time) {
|
|
TRACE_EVENT0("flutter", "Engine::BeginFrame");
|
|
runtime_controller_->BeginFrame(frame_time);
|
|
}
|
|
|
|
void Engine::ReportTimings(std::vector<int64_t> timings) {
|
|
TRACE_EVENT0("flutter", "Engine::ReportTimings");
|
|
runtime_controller_->ReportTimings(std::move(timings));
|
|
}
|
|
|
|
void Engine::HintFreed(size_t size) {
|
|
hint_freed_bytes_since_last_call_ += size;
|
|
}
|
|
|
|
void Engine::NotifyIdle(int64_t deadline) {
|
|
auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros());
|
|
TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
|
|
trace_event.c_str());
|
|
// Avoid asking the RuntimeController to call Dart_HintFreed more than once
|
|
// every 5 seconds.
|
|
// This is to avoid GCs happening too frequently e.g. when an animated GIF is
|
|
// playing and disposing of an image every frame.
|
|
fml::TimePoint now = delegate_.GetCurrentTimePoint();
|
|
fml::TimeDelta delta = now - last_hint_freed_call_time_;
|
|
size_t hint_freed_bytes = 0;
|
|
if (delta.ToMilliseconds() > 5000 && hint_freed_bytes_since_last_call_ > 0) {
|
|
hint_freed_bytes = hint_freed_bytes_since_last_call_;
|
|
hint_freed_bytes_since_last_call_ = 0;
|
|
last_hint_freed_call_time_ = now;
|
|
}
|
|
runtime_controller_->NotifyIdle(deadline, hint_freed_bytes);
|
|
}
|
|
|
|
std::optional<uint32_t> Engine::GetUIIsolateReturnCode() {
|
|
return runtime_controller_->GetRootIsolateReturnCode();
|
|
}
|
|
|
|
Dart_Port Engine::GetUIIsolateMainPort() {
|
|
return runtime_controller_->GetMainPort();
|
|
}
|
|
|
|
std::string Engine::GetUIIsolateName() {
|
|
return runtime_controller_->GetIsolateName();
|
|
}
|
|
|
|
bool Engine::UIIsolateHasLivePorts() {
|
|
return runtime_controller_->HasLivePorts();
|
|
}
|
|
|
|
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
|
|
return runtime_controller_->GetLastError();
|
|
}
|
|
|
|
void Engine::OnOutputSurfaceCreated() {
|
|
have_surface_ = true;
|
|
StartAnimatorIfPossible();
|
|
ScheduleFrame();
|
|
}
|
|
|
|
void Engine::OnOutputSurfaceDestroyed() {
|
|
have_surface_ = false;
|
|
StopAnimator();
|
|
}
|
|
|
|
void Engine::SetViewportMetrics(const ViewportMetrics& metrics) {
|
|
bool dimensions_changed =
|
|
viewport_metrics_.physical_height != metrics.physical_height ||
|
|
viewport_metrics_.physical_width != metrics.physical_width ||
|
|
viewport_metrics_.device_pixel_ratio != metrics.device_pixel_ratio;
|
|
viewport_metrics_ = metrics;
|
|
runtime_controller_->SetViewportMetrics(viewport_metrics_);
|
|
if (animator_) {
|
|
if (dimensions_changed) {
|
|
animator_->SetDimensionChangePending();
|
|
}
|
|
if (have_surface_) {
|
|
ScheduleFrame();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Engine::DispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) {
|
|
std::string channel = message->channel();
|
|
if (channel == kLifecycleChannel) {
|
|
if (HandleLifecyclePlatformMessage(message.get())) {
|
|
return;
|
|
}
|
|
} else if (channel == kLocalizationChannel) {
|
|
if (HandleLocalizationPlatformMessage(message.get())) {
|
|
return;
|
|
}
|
|
} else if (channel == kSettingsChannel) {
|
|
HandleSettingsPlatformMessage(message.get());
|
|
return;
|
|
} else if (!runtime_controller_->IsRootIsolateRunning() &&
|
|
channel == kNavigationChannel) {
|
|
// If there's no runtime_, we may still need to set the initial route.
|
|
HandleNavigationPlatformMessage(std::move(message));
|
|
return;
|
|
}
|
|
|
|
if (runtime_controller_->IsRootIsolateRunning() &&
|
|
runtime_controller_->DispatchPlatformMessage(std::move(message))) {
|
|
return;
|
|
}
|
|
|
|
FML_DLOG(WARNING) << "Dropping platform message on channel: " << channel;
|
|
}
|
|
|
|
bool Engine::HandleLifecyclePlatformMessage(PlatformMessage* message) {
|
|
const auto& data = message->data();
|
|
std::string state(reinterpret_cast<const char*>(data.GetMapping()),
|
|
data.GetSize());
|
|
if (state == "AppLifecycleState.paused" ||
|
|
state == "AppLifecycleState.detached") {
|
|
activity_running_ = false;
|
|
StopAnimator();
|
|
} else if (state == "AppLifecycleState.resumed" ||
|
|
state == "AppLifecycleState.inactive") {
|
|
activity_running_ = true;
|
|
StartAnimatorIfPossible();
|
|
}
|
|
|
|
// Always schedule a frame when the app does become active as per API
|
|
// recommendation
|
|
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive?language=objc
|
|
if (state == "AppLifecycleState.resumed" && have_surface_) {
|
|
ScheduleFrame();
|
|
}
|
|
runtime_controller_->SetLifecycleState(state);
|
|
// Always forward these messages to the framework by returning false.
|
|
return false;
|
|
}
|
|
|
|
bool Engine::HandleNavigationPlatformMessage(
|
|
std::unique_ptr<PlatformMessage> message) {
|
|
const auto& data = message->data();
|
|
|
|
rapidjson::Document document;
|
|
document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
|
|
data.GetSize());
|
|
if (document.HasParseError() || !document.IsObject()) {
|
|
return false;
|
|
}
|
|
auto root = document.GetObject();
|
|
auto method = root.FindMember("method");
|
|
if (method->value != "setInitialRoute") {
|
|
return false;
|
|
}
|
|
auto route = root.FindMember("args");
|
|
initial_route_ = std::move(route->value.GetString());
|
|
return true;
|
|
}
|
|
|
|
bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) {
|
|
const auto& data = message->data();
|
|
|
|
rapidjson::Document document;
|
|
document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
|
|
data.GetSize());
|
|
if (document.HasParseError() || !document.IsObject()) {
|
|
return false;
|
|
}
|
|
auto root = document.GetObject();
|
|
auto method = root.FindMember("method");
|
|
if (method == root.MemberEnd()) {
|
|
return false;
|
|
}
|
|
const size_t strings_per_locale = 4;
|
|
if (method->value == "setLocale") {
|
|
// Decode and pass the list of locale data onwards to dart.
|
|
auto args = root.FindMember("args");
|
|
if (args == root.MemberEnd() || !args->value.IsArray()) {
|
|
return false;
|
|
}
|
|
|
|
if (args->value.Size() % strings_per_locale != 0) {
|
|
return false;
|
|
}
|
|
std::vector<std::string> locale_data;
|
|
for (size_t locale_index = 0; locale_index < args->value.Size();
|
|
locale_index += strings_per_locale) {
|
|
if (!args->value[locale_index].IsString() ||
|
|
!args->value[locale_index + 1].IsString()) {
|
|
return false;
|
|
}
|
|
locale_data.push_back(args->value[locale_index].GetString());
|
|
locale_data.push_back(args->value[locale_index + 1].GetString());
|
|
locale_data.push_back(args->value[locale_index + 2].GetString());
|
|
locale_data.push_back(args->value[locale_index + 3].GetString());
|
|
}
|
|
|
|
return runtime_controller_->SetLocales(locale_data);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
|
|
const auto& data = message->data();
|
|
std::string jsonData(reinterpret_cast<const char*>(data.GetMapping()),
|
|
data.GetSize());
|
|
if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) &&
|
|
have_surface_) {
|
|
ScheduleFrame();
|
|
}
|
|
}
|
|
|
|
void Engine::DispatchPointerDataPacket(
|
|
std::unique_ptr<PointerDataPacket> packet,
|
|
uint64_t trace_flow_id) {
|
|
TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
|
|
TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
|
|
pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
|
|
}
|
|
|
|
void Engine::DispatchKeyDataPacket(std::unique_ptr<KeyDataPacket> packet,
|
|
KeyDataResponse callback) {
|
|
TRACE_EVENT0("flutter", "Engine::DispatchKeyDataPacket");
|
|
if (runtime_controller_) {
|
|
runtime_controller_->DispatchKeyDataPacket(*packet, std::move(callback));
|
|
}
|
|
}
|
|
|
|
void Engine::DispatchSemanticsAction(int id,
|
|
SemanticsAction action,
|
|
fml::MallocMapping args) {
|
|
runtime_controller_->DispatchSemanticsAction(id, action, std::move(args));
|
|
}
|
|
|
|
void Engine::SetSemanticsEnabled(bool enabled) {
|
|
runtime_controller_->SetSemanticsEnabled(enabled);
|
|
}
|
|
|
|
void Engine::SetAccessibilityFeatures(int32_t flags) {
|
|
runtime_controller_->SetAccessibilityFeatures(flags);
|
|
}
|
|
|
|
void Engine::StopAnimator() {
|
|
animator_->Stop();
|
|
}
|
|
|
|
void Engine::StartAnimatorIfPossible() {
|
|
if (activity_running_ && have_surface_) {
|
|
animator_->Start();
|
|
}
|
|
}
|
|
|
|
std::string Engine::DefaultRouteName() {
|
|
if (!initial_route_.empty()) {
|
|
return initial_route_;
|
|
}
|
|
return "/";
|
|
}
|
|
|
|
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
|
|
animator_->RequestFrame(regenerate_layer_tree);
|
|
}
|
|
|
|
void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
|
|
if (!layer_tree) {
|
|
return;
|
|
}
|
|
|
|
// Ensure frame dimensions are sane.
|
|
if (layer_tree->frame_size().isEmpty() ||
|
|
layer_tree->device_pixel_ratio() <= 0.0f) {
|
|
return;
|
|
}
|
|
|
|
animator_->Render(std::move(layer_tree));
|
|
}
|
|
|
|
void Engine::UpdateSemantics(SemanticsNodeUpdates update,
|
|
CustomAccessibilityActionUpdates actions) {
|
|
delegate_.OnEngineUpdateSemantics(std::move(update), std::move(actions));
|
|
}
|
|
|
|
void Engine::HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) {
|
|
if (message->channel() == kAssetChannel) {
|
|
HandleAssetPlatformMessage(std::move(message));
|
|
} else {
|
|
delegate_.OnEngineHandlePlatformMessage(std::move(message));
|
|
}
|
|
}
|
|
|
|
void Engine::OnRootIsolateCreated() {
|
|
delegate_.OnRootIsolateCreated();
|
|
}
|
|
|
|
void Engine::UpdateIsolateDescription(const std::string isolate_name,
|
|
int64_t isolate_port) {
|
|
delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
|
|
}
|
|
|
|
std::unique_ptr<std::vector<std::string>> Engine::ComputePlatformResolvedLocale(
|
|
const std::vector<std::string>& supported_locale_data) {
|
|
return delegate_.ComputePlatformResolvedLocale(supported_locale_data);
|
|
}
|
|
|
|
void Engine::SetNeedsReportTimings(bool needs_reporting) {
|
|
delegate_.SetNeedsReportTimings(needs_reporting);
|
|
}
|
|
|
|
FontCollection& Engine::GetFontCollection() {
|
|
return *font_collection_;
|
|
}
|
|
|
|
void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
|
|
uint64_t trace_flow_id) {
|
|
animator_->EnqueueTraceFlowId(trace_flow_id);
|
|
if (runtime_controller_) {
|
|
runtime_controller_->DispatchPointerDataPacket(*packet);
|
|
}
|
|
}
|
|
|
|
void Engine::ScheduleSecondaryVsyncCallback(uintptr_t id,
|
|
const fml::closure& callback) {
|
|
animator_->ScheduleSecondaryVsyncCallback(id, callback);
|
|
}
|
|
|
|
void Engine::HandleAssetPlatformMessage(
|
|
std::unique_ptr<PlatformMessage> message) {
|
|
fml::RefPtr<PlatformMessageResponse> response = message->response();
|
|
if (!response) {
|
|
return;
|
|
}
|
|
const auto& data = message->data();
|
|
std::string asset_name(reinterpret_cast<const char*>(data.GetMapping()),
|
|
data.GetSize());
|
|
|
|
if (asset_manager_) {
|
|
std::unique_ptr<fml::Mapping> asset_mapping =
|
|
asset_manager_->GetAsMapping(asset_name);
|
|
if (asset_mapping) {
|
|
response->Complete(std::move(asset_mapping));
|
|
return;
|
|
}
|
|
}
|
|
|
|
response->CompleteEmpty();
|
|
}
|
|
|
|
const std::string& Engine::GetLastEntrypoint() const {
|
|
return last_entry_point_;
|
|
}
|
|
|
|
const std::string& Engine::GetLastEntrypointLibrary() const {
|
|
return last_entry_point_library_;
|
|
}
|
|
|
|
// |RuntimeDelegate|
|
|
void Engine::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
|
|
return delegate_.RequestDartDeferredLibrary(loading_unit_id);
|
|
}
|
|
|
|
void Engine::LoadDartDeferredLibrary(
|
|
intptr_t loading_unit_id,
|
|
std::unique_ptr<const fml::Mapping> snapshot_data,
|
|
std::unique_ptr<const fml::Mapping> snapshot_instructions) {
|
|
if (runtime_controller_->IsRootIsolateRunning()) {
|
|
runtime_controller_->LoadDartDeferredLibrary(
|
|
loading_unit_id, std::move(snapshot_data),
|
|
std::move(snapshot_instructions));
|
|
} else {
|
|
LoadDartDeferredLibraryError(loading_unit_id, "No running root isolate.",
|
|
true);
|
|
}
|
|
}
|
|
|
|
void Engine::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
|
|
const std::string error_message,
|
|
bool transient) {
|
|
if (runtime_controller_->IsRootIsolateRunning()) {
|
|
runtime_controller_->LoadDartDeferredLibraryError(loading_unit_id,
|
|
error_message, transient);
|
|
}
|
|
}
|
|
|
|
} // namespace flutter
|