flutter_flutter/engine/src/flutter/testing/dart_isolate_runner.cc
Brandon DeRosier a83c8ab61d Refactor: Group together externally-managed UIDartState. (flutter/engine#26247)
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.
2021-05-20 18:01:53 -07:00

175 lines
5.3 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/testing/dart_isolate_runner.h"
#include "flutter/runtime/isolate_configuration.h"
namespace flutter {
namespace testing {
AutoIsolateShutdown::AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
fml::RefPtr<fml::TaskRunner> runner)
: isolate_(std::move(isolate)), runner_(std::move(runner)) {}
AutoIsolateShutdown::~AutoIsolateShutdown() {
if (!isolate_->IsShuttingDown()) {
Shutdown();
}
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(runner_, [this, &latch]() {
// Delete isolate on thread.
isolate_.reset();
latch.Signal();
});
latch.Wait();
}
void AutoIsolateShutdown::Shutdown() {
if (!IsValid()) {
return;
}
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
runner_, [isolate = isolate_.get(), &latch]() {
if (!isolate->Shutdown()) {
FML_LOG(ERROR) << "Could not shutdown isolate.";
FML_CHECK(false);
}
latch.Signal();
});
latch.Wait();
}
[[nodiscard]] bool AutoIsolateShutdown::RunInIsolateScope(
std::function<bool(void)> closure) {
if (!IsValid()) {
return false;
}
bool result = false;
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
runner_, [this, &result, &latch, closure]() {
tonic::DartIsolateScope scope(isolate_->isolate());
tonic::DartApiScope api_scope;
if (closure) {
result = closure();
}
latch.Signal();
});
latch.Wait();
return true;
}
std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolateOnUITaskRunner(
DartVMRef& vm_ref,
const Settings& p_settings,
const TaskRunners& task_runners,
std::string entrypoint,
const std::vector<std::string>& args,
const std::string& kernel_file_path,
fml::WeakPtr<IOManager> io_manager,
std::shared_ptr<VolatilePathTracker> volatile_path_tracker) {
FML_CHECK(task_runners.GetUITaskRunner()->RunsTasksOnCurrentThread());
if (!vm_ref) {
return nullptr;
}
auto vm_data = vm_ref.GetVMData();
if (!vm_data) {
return nullptr;
}
auto settings = p_settings;
settings.dart_entrypoint_args = args;
if (!DartVM::IsRunningPrecompiledCode()) {
if (!fml::IsFile(kernel_file_path)) {
FML_LOG(ERROR) << "Could not locate kernel file.";
return nullptr;
}
auto kernel_file = fml::OpenFile(kernel_file_path.c_str(), false,
fml::FilePermission::kRead);
if (!kernel_file.is_valid()) {
FML_LOG(ERROR) << "Kernel file descriptor was invalid.";
return nullptr;
}
auto kernel_mapping = std::make_unique<fml::FileMapping>(kernel_file);
if (kernel_mapping->GetMapping() == nullptr) {
FML_LOG(ERROR) << "Could not set up kernel mapping.";
return nullptr;
}
settings.application_kernels = fml::MakeCopyable(
[kernel_mapping = std::move(kernel_mapping)]() mutable -> Mappings {
Mappings mappings;
mappings.emplace_back(std::move(kernel_mapping));
return mappings;
});
}
auto isolate_configuration =
IsolateConfiguration::InferFromSettings(settings);
UIDartState::Context context(std::move(task_runners));
context.io_manager = io_manager;
context.advisory_script_uri = "main.dart";
context.advisory_script_entrypoint = entrypoint.c_str();
auto isolate =
DartIsolate::CreateRunningRootIsolate(
settings, // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
nullptr, // platform configuration
DartIsolate::Flags{}, // flags
settings.isolate_create_callback, // isolate create callback
settings.isolate_shutdown_callback, // isolate shutdown callback
entrypoint, // entrypoint
std::nullopt, // library
std::move(isolate_configuration), // isolate configuration
context // engine context
)
.lock();
if (!isolate) {
FML_LOG(ERROR) << "Could not create running isolate.";
return nullptr;
}
return std::make_unique<AutoIsolateShutdown>(isolate,
task_runners.GetUITaskRunner());
}
std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
DartVMRef& vm_ref,
const Settings& settings,
const TaskRunners& task_runners,
std::string entrypoint,
const std::vector<std::string>& args,
const std::string& kernel_file_path,
fml::WeakPtr<IOManager> io_manager,
std::shared_ptr<VolatilePathTracker> volatile_path_tracker) {
std::unique_ptr<AutoIsolateShutdown> result;
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetUITaskRunner(), fml::MakeCopyable([&]() mutable {
result = RunDartCodeInIsolateOnUITaskRunner(
vm_ref, settings, task_runners, entrypoint, args, kernel_file_path,
io_manager, std::move(volatile_path_tracker));
latch.Signal();
}));
latch.Wait();
return result;
}
} // namespace testing
} // namespace flutter