Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions testing/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ source_set("dart") {
testonly = true

sources = [
"dart_isolate_runner.cc",
"dart_isolate_runner.h",
"elf_loader.cc",
"elf_loader.h",
Expand Down
176 changes: 176 additions & 0 deletions testing/dart_isolate_runner.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// 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"

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 (!IsValid()) {
return;
}
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
runner_, [isolate = std::move(isolate_), &latch]() {
if (!isolate->Shutdown()) {
FML_LOG(ERROR) << "Could not shutdown isolate.";
FML_CHECK(false);
}
latch.Signal();
});
latch.Wait();
}

FML_WARN_UNUSED_RESULT
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;
}

void RunDartCodeInIsolate(DartVMRef& vm_ref,
std::unique_ptr<AutoIsolateShutdown>& result,
const Settings& settings,
const TaskRunners& task_runners,
std::string entrypoint,
const std::vector<std::string>& args,
const std::string& fixtures_path,
fml::WeakPtr<IOManager> io_manager) {
FML_CHECK(task_runners.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

if (!vm_ref) {
return;
}

auto vm_data = vm_ref.GetVMData();

if (!vm_data) {
return;
}

auto weak_isolate = DartIsolate::CreateRootIsolate(
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
io_manager, // io manager
{}, // unref queue
{}, // image decoder
"main.dart", // advisory uri
"main", // advisory entrypoint
nullptr, // flags
settings.isolate_create_callback, // isolate create callback
settings.isolate_shutdown_callback // isolate shutdown callback
);

auto root_isolate = std::make_unique<AutoIsolateShutdown>(
weak_isolate.lock(), task_runners.GetUITaskRunner());

if (!root_isolate->IsValid()) {
FML_LOG(ERROR) << "Could not create isolate.";
return;
}

if (root_isolate->get()->GetPhase() != DartIsolate::Phase::LibrariesSetup) {
FML_LOG(ERROR) << "Created isolate is in unexpected phase.";
return;
}

if (!DartVM::IsRunningPrecompiledCode()) {
auto kernel_file_path =
fml::paths::JoinPaths({fixtures_path, "kernel_blob.bin"});

if (!fml::IsFile(kernel_file_path)) {
FML_LOG(ERROR) << "Could not locate kernel file.";
return;
}

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;
}

auto kernel_mapping = std::make_unique<fml::FileMapping>(kernel_file);

if (kernel_mapping->GetMapping() == nullptr) {
FML_LOG(ERROR) << "Could not setup kernel mapping.";
return;
}

if (!root_isolate->get()->PrepareForRunningFromKernel(
std::move(kernel_mapping))) {
FML_LOG(ERROR)
<< "Could not prepare to run the isolate from the kernel file.";
return;
}
} else {
if (!root_isolate->get()->PrepareForRunningFromPrecompiledCode()) {
FML_LOG(ERROR)
<< "Could not prepare to run the isolate from precompiled code.";
return;
}
}

if (root_isolate->get()->GetPhase() != DartIsolate::Phase::Ready) {
FML_LOG(ERROR) << "Isolate is in unexpected phase.";
return;
}

if (!root_isolate->get()->Run(entrypoint, args,
settings.root_isolate_create_callback)) {
FML_LOG(ERROR) << "Could not run the method \"" << entrypoint
<< "\" in the isolate.";
return;
}

root_isolate->get()->AddIsolateShutdownCallback(
settings.root_isolate_shutdown_callback);

result = std::move(root_isolate);
}

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& fixtures_path,
fml::WeakPtr<IOManager> io_manager) {
std::unique_ptr<AutoIsolateShutdown> result;
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetPlatformTaskRunner(), fml::MakeCopyable([&]() mutable {
RunDartCodeInIsolate(vm_ref, result, settings, task_runners, entrypoint,
args, fixtures_path, io_manager);
latch.Signal();
}));
latch.Wait();
return result;
}

} // namespace testing
} // namespace flutter
175 changes: 22 additions & 153 deletions testing/dart_isolate_runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_TESTING_DART_ISOLATE_RUNNER_H_
#define FLUTTER_TESTING_DART_ISOLATE_RUNNER_H_

#include "flutter/common/task_runners.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/thread.h"
#include "flutter/runtime/dart_isolate.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"

namespace flutter {
namespace testing {
Expand All @@ -15,47 +22,14 @@ class AutoIsolateShutdown {
AutoIsolateShutdown() = default;

AutoIsolateShutdown(std::shared_ptr<DartIsolate> isolate,
fml::RefPtr<fml::TaskRunner> runner)
: isolate_(std::move(isolate)), runner_(std::move(runner)) {}
fml::RefPtr<fml::TaskRunner> runner);

~AutoIsolateShutdown() {
if (!IsValid()) {
return;
}
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
runner_, [isolate = std::move(isolate_), &latch]() {
if (!isolate->Shutdown()) {
FML_LOG(ERROR) << "Could not shutdown isolate.";
FML_CHECK(false);
}
latch.Signal();
});
latch.Wait();
}
~AutoIsolateShutdown();

bool IsValid() const { return isolate_ != nullptr && runner_; }

FML_WARN_UNUSED_RESULT
bool 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;
}
bool RunInIsolateScope(std::function<bool(void)> closure);

DartIsolate* get() {
FML_CHECK(isolate_);
Expand All @@ -69,130 +43,25 @@ class AutoIsolateShutdown {
FML_DISALLOW_COPY_AND_ASSIGN(AutoIsolateShutdown);
};

static void RunDartCodeInIsolate(DartVMRef& vm_ref,
std::unique_ptr<AutoIsolateShutdown>& result,
const Settings& settings,
const TaskRunners& task_runners,
std::string entrypoint,
const std::vector<std::string>& args,
const std::string& fixtures_path,
fml::WeakPtr<IOManager> io_manager = {}) {
FML_CHECK(task_runners.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());

if (!vm_ref) {
return;
}

auto vm_data = vm_ref.GetVMData();

if (!vm_data) {
return;
}

auto weak_isolate = DartIsolate::CreateRootIsolate(
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
io_manager, // io manager
{}, // unref queue
{}, // image decoder
"main.dart", // advisory uri
"main", // advisory entrypoint
nullptr, // flags
settings.isolate_create_callback, // isolate create callback
settings.isolate_shutdown_callback // isolate shutdown callback
);

auto root_isolate = std::make_unique<AutoIsolateShutdown>(
weak_isolate.lock(), task_runners.GetUITaskRunner());

if (!root_isolate->IsValid()) {
FML_LOG(ERROR) << "Could not create isolate.";
return;
}

if (root_isolate->get()->GetPhase() != DartIsolate::Phase::LibrariesSetup) {
FML_LOG(ERROR) << "Created isolate is in unexpected phase.";
return;
}

if (!DartVM::IsRunningPrecompiledCode()) {
auto kernel_file_path =
fml::paths::JoinPaths({fixtures_path, "kernel_blob.bin"});

if (!fml::IsFile(kernel_file_path)) {
FML_LOG(ERROR) << "Could not locate kernel file.";
return;
}

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;
}

auto kernel_mapping = std::make_unique<fml::FileMapping>(kernel_file);

if (kernel_mapping->GetMapping() == nullptr) {
FML_LOG(ERROR) << "Could not setup kernel mapping.";
return;
}

if (!root_isolate->get()->PrepareForRunningFromKernel(
std::move(kernel_mapping))) {
FML_LOG(ERROR)
<< "Could not prepare to run the isolate from the kernel file.";
return;
}
} else {
if (!root_isolate->get()->PrepareForRunningFromPrecompiledCode()) {
FML_LOG(ERROR)
<< "Could not prepare to run the isolate from precompiled code.";
return;
}
}
void RunDartCodeInIsolate(DartVMRef& vm_ref,
std::unique_ptr<AutoIsolateShutdown>& result,
const Settings& settings,
const TaskRunners& task_runners,
std::string entrypoint,
const std::vector<std::string>& args,
const std::string& fixtures_path,
fml::WeakPtr<IOManager> io_manager = {});

if (root_isolate->get()->GetPhase() != DartIsolate::Phase::Ready) {
FML_LOG(ERROR) << "Isolate is in unexpected phase.";
return;
}

if (!root_isolate->get()->Run(entrypoint, args,
settings.root_isolate_create_callback)) {
FML_LOG(ERROR) << "Could not run the method \"" << entrypoint
<< "\" in the isolate.";
return;
}

root_isolate->get()->AddIsolateShutdownCallback(
settings.root_isolate_shutdown_callback);

result = std::move(root_isolate);
}

static std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
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& fixtures_path,
fml::WeakPtr<IOManager> io_manager = {}) {
std::unique_ptr<AutoIsolateShutdown> result;
fml::AutoResetWaitableEvent latch;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetPlatformTaskRunner(), fml::MakeCopyable([&]() mutable {
RunDartCodeInIsolate(vm_ref, result, settings, task_runners, entrypoint,
args, fixtures_path, io_manager);
latch.Signal();
}));
latch.Wait();
return result;
}
fml::WeakPtr<IOManager> io_manager = {});

} // namespace testing
} // namespace flutter

#endif // FLUTTER_TESTING_DART_ISOLATE_RUNNER_H_