Shut down and restart the Dart VM as needed. (flutter/engine#7832)

The shell was already designed to cleanly shut down the VM but it couldnt
earlier as |Dart_Initialize| could never be called after a |Dart_Cleanup|. This
meant that shutting down an engine instance could not shut down the VM to save
memory because newly created engines in the process after that point couldn't
restart the VM. There can only be one VM running in a process at a time.

This patch separate the previous DartVM object into one that references a
running instance of the DartVM and a set of immutable dependencies that
components can reference even as the VM is shutting down.

Unit tests have been added to assert that non-overlapping engine launches use
difference VM instances.
This commit is contained in:
Chinmay Garde
2019-02-15 14:16:17 -08:00
committed by GitHub
parent 914dc5a0b6
commit 75a66f31dc
23 changed files with 742 additions and 321 deletions

View File

@@ -355,6 +355,10 @@ FILE: ../../../flutter/runtime/dart_snapshot_buffer.cc
FILE: ../../../flutter/runtime/dart_snapshot_buffer.h
FILE: ../../../flutter/runtime/dart_vm.cc
FILE: ../../../flutter/runtime/dart_vm.h
FILE: ../../../flutter/runtime/dart_vm_data.cc
FILE: ../../../flutter/runtime/dart_vm_data.h
FILE: ../../../flutter/runtime/dart_vm_lifecycle.cc
FILE: ../../../flutter/runtime/dart_vm_lifecycle.h
FILE: ../../../flutter/runtime/dart_vm_unittests.cc
FILE: ../../../flutter/runtime/embedder_resources.cc
FILE: ../../../flutter/runtime/embedder_resources.h

View File

@@ -14,8 +14,10 @@ namespace blink {
Dart_Handle IsolateNameServerNatives::LookupPortByName(
const std::string& name) {
IsolateNameServer* name_server =
UIDartState::Current()->GetIsolateNameServer();
auto name_server = UIDartState::Current()->GetIsolateNameServer();
if (!name_server) {
return Dart_Null();
}
Dart_Port port = name_server->LookupIsolatePortByName(name);
if (port == ILLEGAL_PORT) {
return Dart_Null();
@@ -26,8 +28,10 @@ Dart_Handle IsolateNameServerNatives::LookupPortByName(
Dart_Handle IsolateNameServerNatives::RegisterPortWithName(
Dart_Handle port_handle,
const std::string& name) {
IsolateNameServer* name_server =
UIDartState::Current()->GetIsolateNameServer();
auto name_server = UIDartState::Current()->GetIsolateNameServer();
if (!name_server) {
return Dart_False();
}
Dart_Port port = ILLEGAL_PORT;
Dart_SendPortGetId(port_handle, &port);
if (!name_server->RegisterIsolatePortWithName(port, name)) {
@@ -38,8 +42,10 @@ Dart_Handle IsolateNameServerNatives::RegisterPortWithName(
Dart_Handle IsolateNameServerNatives::RemovePortNameMapping(
const std::string& name) {
IsolateNameServer* name_server =
UIDartState::Current()->GetIsolateNameServer();
auto name_server = UIDartState::Current()->GetIsolateNameServer();
if (!name_server) {
return Dart_False();
}
if (!name_server->RemoveIsolateNameMapping(name)) {
return Dart_False();
}

View File

@@ -23,7 +23,7 @@ UIDartState::UIDartState(
std::string advisory_script_entrypoint,
std::string logger_prefix,
UnhandledExceptionCallback unhandled_exception_callback,
IsolateNameServer* isolate_name_server)
std::shared_ptr<IsolateNameServer> isolate_name_server)
: task_runners_(std::move(task_runners)),
add_callback_(std::move(add_callback)),
remove_callback_(std::move(remove_callback)),
@@ -33,7 +33,7 @@ UIDartState::UIDartState(
advisory_script_entrypoint_(std::move(advisory_script_entrypoint)),
logger_prefix_(std::move(logger_prefix)),
unhandled_exception_callback_(unhandled_exception_callback),
isolate_name_server_(isolate_name_server) {
isolate_name_server_(std::move(isolate_name_server)) {
AddOrRemoveTaskObserver(true /* add */);
}
@@ -124,7 +124,7 @@ fml::WeakPtr<GrContext> UIDartState::GetResourceContext() const {
return io_manager_->GetResourceContext();
}
IsolateNameServer* UIDartState::GetIsolateNameServer() {
std::shared_ptr<IsolateNameServer> UIDartState::GetIsolateNameServer() const {
return isolate_name_server_;
}

View File

@@ -53,7 +53,7 @@ class UIDartState : public tonic::DartState {
fml::WeakPtr<GrContext> GetResourceContext() const;
IsolateNameServer* GetIsolateNameServer();
std::shared_ptr<IsolateNameServer> GetIsolateNameServer() const;
tonic::DartErrorHandleType GetLastError();
@@ -81,7 +81,7 @@ class UIDartState : public tonic::DartState {
std::string advisory_script_entrypoint,
std::string logger_prefix,
UnhandledExceptionCallback unhandled_exception_callback,
IsolateNameServer* isolate_name_server);
std::shared_ptr<IsolateNameServer> isolate_name_server);
~UIDartState() override;
@@ -107,7 +107,7 @@ class UIDartState : public tonic::DartState {
std::unique_ptr<Window> window_;
tonic::DartMicrotaskQueue microtask_queue_;
UnhandledExceptionCallback unhandled_exception_callback_;
IsolateNameServer* isolate_name_server_;
const std::shared_ptr<IsolateNameServer> isolate_name_server_;
void AddOrRemoveTaskObserver(bool add);
};

View File

@@ -36,6 +36,10 @@ source_set("runtime") {
"dart_snapshot_buffer.h",
"dart_vm.cc",
"dart_vm.h",
"dart_vm_data.cc",
"dart_vm_data.h",
"dart_vm_lifecycle.cc",
"dart_vm_lifecycle.h",
"embedder_resources.cc",
"embedder_resources.h",
"runtime_controller.cc",
@@ -73,7 +77,9 @@ source_set("runtime") {
flutter_runtime_mode != "dynamic_release" && !is_fuchsia) {
# Only link in Observatory in non-release modes on non-Fuchsia. Fuchsia
# instead puts Observatory into the runner's package.
deps += [ "//third_party/dart/runtime/observatory:embedded_observatory_archive" ]
deps += [
"//third_party/dart/runtime/observatory:embedded_observatory_archive",
]
}
}
@@ -95,6 +101,7 @@ executable("runtime_unittests") {
":runtime_fixtures",
"$flutter_root/fml",
"$flutter_root/lib/snapshot",
"$flutter_root/shell/common",
"$flutter_root/testing",
"//third_party/dart/runtime:libdart_jit",
"//third_party/skia",

View File

@@ -14,6 +14,7 @@
#include "flutter/lib/ui/dart_ui.h"
#include "flutter/runtime/dart_service_isolate.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "third_party/dart/runtime/include/dart_api.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "third_party/tonic/converter/dart_converter.h"
@@ -29,9 +30,9 @@
namespace blink {
std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
DartVM* vm,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
const Settings& settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
TaskRunners task_runners,
std::unique_ptr<Window> window,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
@@ -50,7 +51,7 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
// isolate lifecycle is entirely managed by the VM).
auto root_embedder_data = std::make_unique<std::shared_ptr<DartIsolate>>(
std::make_shared<DartIsolate>(
vm, // VM
settings, // settings
std::move(isolate_snapshot), // isolate snapshot
std::move(shared_snapshot), // shared snapshot
task_runners, // task runners
@@ -93,9 +94,9 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
return embedder_isolate;
}
DartIsolate::DartIsolate(DartVM* vm,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
DartIsolate::DartIsolate(const Settings& settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
@@ -103,36 +104,31 @@ DartIsolate::DartIsolate(DartVM* vm,
std::string advisory_script_entrypoint,
ChildIsolatePreparer child_isolate_preparer)
: UIDartState(std::move(task_runners),
vm->GetSettings().task_observer_add,
vm->GetSettings().task_observer_remove,
settings.task_observer_add,
settings.task_observer_remove,
std::move(snapshot_delegate),
std::move(io_manager),
advisory_script_uri,
advisory_script_entrypoint,
vm->GetSettings().log_tag,
vm->GetSettings().unhandled_exception_callback,
vm->GetIsolateNameServer()),
vm_(vm),
settings.log_tag,
settings.unhandled_exception_callback,
DartVMRef::GetIsolateNameServer()),
settings_(settings),
isolate_snapshot_(std::move(isolate_snapshot)),
shared_snapshot_(std::move(shared_snapshot)),
child_isolate_preparer_(std::move(child_isolate_preparer)) {
FML_DCHECK(isolate_snapshot_) << "Must contain a valid isolate snapshot.";
if (vm_ == nullptr) {
return;
}
phase_ = Phase::Uninitialized;
}
DartIsolate::~DartIsolate() = default;
DartIsolate::Phase DartIsolate::GetPhase() const {
return phase_;
const Settings& DartIsolate::GetSettings() const {
return settings_;
}
DartVM* DartIsolate::GetDartVM() const {
return vm_;
DartIsolate::Phase DartIsolate::GetPhase() const {
return phase_;
}
bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) {
@@ -493,16 +489,16 @@ Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
const char* package_config,
Dart_IsolateFlags* flags,
char** error) {
auto vm = DartVM::ForProcessIfInitialized();
auto vm_data = DartVMRef::GetVMData();
if (!vm) {
if (!vm_data) {
*error = strdup(
"Could not resolve the VM when attempting to create the service "
"isolate.");
"Could not access VM data to initialize isolates. This may be because "
"the VM has initialized shutdown on another thread already.");
return nullptr;
}
const auto& settings = vm->GetSettings();
const auto& settings = vm_data->GetSettings();
if (!settings.enable_observatory) {
FML_DLOG(INFO) << "Observatory is disabled.";
@@ -515,21 +511,26 @@ Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
flags->load_vmservice_library = true;
if (advisory_script_uri == nullptr) {
advisory_script_uri = "";
}
if (advisory_script_entrypoint == nullptr) {
advisory_script_entrypoint = "";
}
std::weak_ptr<DartIsolate> weak_service_isolate =
DartIsolate::CreateRootIsolate(
vm.get(), // vm
vm->GetIsolateSnapshot(), // isolate snapshot
vm->GetSharedSnapshot(), // shared snapshot
null_task_runners, // task runners
nullptr, // window
{}, // snapshot delegate
{}, // IO Manager
advisory_script_uri == nullptr ? ""
: advisory_script_uri, // script uri
advisory_script_entrypoint == nullptr
? ""
: advisory_script_entrypoint, // script entrypoint
flags // flags
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // service isolate snapshot
vm_data->GetSharedSnapshot(), // shared snapshot
null_task_runners, // service isolate task runners
nullptr, // window
{}, // snapshot delegate
{}, // IO Manager
advisory_script_uri, // script uri
advisory_script_entrypoint, // script entrypoint
flags // flags
);
std::shared_ptr<DartIsolate> service_isolate = weak_service_isolate.lock();
@@ -552,7 +553,13 @@ Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
return nullptr;
}
vm->GetServiceProtocol().ToggleHooks(true);
if (auto service_protocol = DartVMRef::GetServiceProtocol()) {
service_protocol->ToggleHooks(true);
} else {
FML_DLOG(ERROR)
<< "Could not acquire the service protocol handlers. This might be "
"because the VM has already begun teardown on another thread.";
}
return service_isolate->isolate();
}
@@ -610,16 +617,13 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair(
std::unique_ptr<std::shared_ptr<DartIsolate>> embedder_isolate(
p_parent_embedder_isolate);
if (embedder_isolate == nullptr ||
(*embedder_isolate)->GetDartVM() == nullptr) {
if (embedder_isolate == nullptr) {
*error =
strdup("Parent isolate did not have embedder specific callback data.");
FML_DLOG(ERROR) << *error;
return {nullptr, {}};
}
DartVM* const vm = (*embedder_isolate)->GetDartVM();
if (!is_root_isolate) {
auto* raw_embedder_isolate = embedder_isolate.release();
@@ -628,7 +632,7 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair(
embedder_isolate = std::make_unique<std::shared_ptr<DartIsolate>>(
std::make_shared<DartIsolate>(
vm, // vm
(*raw_embedder_isolate)->GetSettings(), // settings
(*raw_embedder_isolate)->GetIsolateSnapshot(), // isolate_snapshot
(*raw_embedder_isolate)->GetSharedSnapshot(), // shared_snapshot
null_task_runners, // task_runners
@@ -701,11 +705,11 @@ void DartIsolate::DartIsolateCleanupCallback(
delete embedder_isolate;
}
fml::RefPtr<DartSnapshot> DartIsolate::GetIsolateSnapshot() const {
fml::RefPtr<const DartSnapshot> DartIsolate::GetIsolateSnapshot() const {
return isolate_snapshot_;
}
fml::RefPtr<DartSnapshot> DartIsolate::GetSharedSnapshot() const {
fml::RefPtr<const DartSnapshot> DartIsolate::GetSharedSnapshot() const {
return shared_snapshot_;
}

View File

@@ -41,9 +41,9 @@ class DartIsolate : public UIDartState {
// bindings. From the VM's perspective, this isolate is not special in any
// way.
static std::weak_ptr<DartIsolate> CreateRootIsolate(
DartVM* vm,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
const Settings& settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
TaskRunners task_runners,
std::unique_ptr<Window> window,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
@@ -52,9 +52,9 @@ class DartIsolate : public UIDartState {
std::string advisory_script_entrypoint,
Dart_IsolateFlags* flags = nullptr);
DartIsolate(DartVM* vm,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
DartIsolate(const Settings& settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
@@ -64,6 +64,8 @@ class DartIsolate : public UIDartState {
~DartIsolate() override;
const Settings& GetSettings() const;
Phase GetPhase() const;
FML_WARN_UNUSED_RESULT
@@ -85,11 +87,9 @@ class DartIsolate : public UIDartState {
void AddIsolateShutdownCallback(fml::closure closure);
DartVM* GetDartVM() const;
fml::RefPtr<const DartSnapshot> GetIsolateSnapshot() const;
fml::RefPtr<DartSnapshot> GetIsolateSnapshot() const;
fml::RefPtr<DartSnapshot> GetSharedSnapshot() const;
fml::RefPtr<const DartSnapshot> GetSharedSnapshot() const;
std::weak_ptr<DartIsolate> GetWeakIsolatePtr();
@@ -108,10 +108,10 @@ class DartIsolate : public UIDartState {
};
friend class DartVM;
DartVM* const vm_ = nullptr;
Phase phase_ = Phase::Unknown;
const fml::RefPtr<DartSnapshot> isolate_snapshot_;
const fml::RefPtr<DartSnapshot> shared_snapshot_;
const Settings settings_;
const fml::RefPtr<const DartSnapshot> isolate_snapshot_;
const fml::RefPtr<const DartSnapshot> shared_snapshot_;
std::vector<std::shared_ptr<const fml::Mapping>> kernel_buffers_;
std::vector<std::unique_ptr<AutoFireClosure>> shutdown_callbacks_;
ChildIsolatePreparer child_isolate_preparer_ = nullptr;

View File

@@ -7,15 +7,11 @@
#include "flutter/fml/thread.h"
#include "flutter/runtime/dart_isolate.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/testing/testing.h"
#include "flutter/testing/thread_test.h"
#include "third_party/tonic/scopes/dart_isolate_scope.h"
#define CURRENT_TEST_NAME \
std::string { \
::testing::UnitTest::GetInstance()->current_test_info()->name() \
}
namespace blink {
using DartIsolateTest = ::testing::ThreadTest;
@@ -24,24 +20,26 @@ TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) {
Settings settings = {};
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
auto vm = DartVM::ForProcess(settings);
auto vm = DartVMRef::Create(settings);
ASSERT_TRUE(vm);
TaskRunners task_runners(CURRENT_TEST_NAME, //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner() //
auto vm_data = vm->GetVMData();
ASSERT_TRUE(vm_data);
TaskRunners task_runners(testing::GetCurrentTestName(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner() //
);
auto weak_isolate = DartIsolate::CreateRootIsolate(
vm.get(), // vm
vm->GetIsolateSnapshot(), // isolate snapshot
vm->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
vm_data->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
);
auto root_isolate = weak_isolate.lock();
ASSERT_TRUE(root_isolate);
@@ -53,24 +51,26 @@ TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) {
Settings settings = {};
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
auto vm = DartVM::ForProcess(settings);
auto vm = DartVMRef::Create(settings);
ASSERT_TRUE(vm);
TaskRunners task_runners(CURRENT_TEST_NAME, //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner() //
auto vm_data = vm->GetVMData();
ASSERT_TRUE(vm_data);
TaskRunners task_runners(testing::GetCurrentTestName(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner() //
);
auto weak_isolate = DartIsolate::CreateRootIsolate(
vm.get(), // vm
vm->GetIsolateSnapshot(), // isolate snapshot
vm->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
vm_data->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
);
auto root_isolate = weak_isolate.lock();
ASSERT_TRUE(root_isolate);
@@ -86,8 +86,11 @@ TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) {
class AutoIsolateShutdown {
public:
AutoIsolateShutdown(std::shared_ptr<blink::DartIsolate> isolate)
: isolate_(std::move(isolate)) {}
AutoIsolateShutdown(blink::DartVMRef vm,
std::shared_ptr<blink::DartIsolate> isolate)
: vm_(std::move(vm)), isolate_(std::move(isolate)) {
FML_CHECK(vm_);
}
~AutoIsolateShutdown() {
if (isolate_) {
@@ -119,6 +122,7 @@ class AutoIsolateShutdown {
}
private:
blink::DartVMRef vm_;
std::shared_ptr<blink::DartIsolate> isolate_;
FML_DISALLOW_COPY_AND_ASSIGN(AutoIsolateShutdown);
@@ -128,35 +132,38 @@ std::unique_ptr<AutoIsolateShutdown> RunDartCodeInIsolate(
fml::RefPtr<fml::TaskRunner> task_runner,
std::string entrypoint) {
Settings settings = {};
settings.enable_observatory = true;
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
auto vm = DartVM::ForProcess(settings);
auto vm = DartVMRef::Create(settings);
if (!vm) {
return {};
}
TaskRunners task_runners(CURRENT_TEST_NAME, //
task_runner, //
task_runner, //
task_runner, //
task_runner //
auto vm_data = vm->GetVMData();
TaskRunners task_runners(testing::GetCurrentTestName(), //
task_runner, //
task_runner, //
task_runner, //
task_runner //
);
auto weak_isolate = DartIsolate::CreateRootIsolate(
vm.get(), // vm
vm->GetIsolateSnapshot(), // isolate snapshot
vm->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
vm_data->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
);
auto root_isolate =
std::make_unique<AutoIsolateShutdown>(weak_isolate.lock());
std::make_unique<AutoIsolateShutdown>(std::move(vm), weak_isolate.lock());
if (!root_isolate->IsValid()) {
FML_LOG(ERROR) << "Could not create isolate.";

View File

@@ -15,6 +15,7 @@
#include "flutter/fml/file.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/mapping.h"
#include "flutter/fml/synchronization/thread_annotations.h"
#include "flutter/fml/time/time_delta.h"
#include "flutter/fml/trace_event.h"
#include "flutter/lib/io/dart_io.h"
@@ -239,66 +240,48 @@ static void EmbedderInformationCallback(Dart_EmbedderInformation* info) {
info->name = "Flutter";
}
fml::RefPtr<DartVM> DartVM::ForProcess(Settings settings) {
return ForProcess(settings, nullptr, nullptr, nullptr);
}
static std::once_flag gVMInitialization;
static std::mutex gVMMutex;
static fml::RefPtr<DartVM> gVM;
fml::RefPtr<DartVM> DartVM::ForProcess(
std::shared_ptr<DartVM> DartVM::Create(
Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot) {
std::lock_guard<std::mutex> lock(gVMMutex);
std::call_once(gVMInitialization, [settings, //
vm_snapshot, //
isolate_snapshot, //
shared_snapshot //
]() mutable {
if (!vm_snapshot) {
vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings);
}
if (!(vm_snapshot && vm_snapshot->IsValid())) {
FML_LOG(ERROR) << "VM snapshot must be valid.";
return;
}
if (!isolate_snapshot) {
isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings);
}
if (!(isolate_snapshot && isolate_snapshot->IsValid())) {
FML_LOG(ERROR) << "Isolate snapshot must be valid.";
return;
}
if (!shared_snapshot) {
shared_snapshot = DartSnapshot::Empty();
}
gVM = fml::MakeRefCounted<DartVM>(settings, //
std::move(vm_snapshot), //
std::move(isolate_snapshot), //
std::move(shared_snapshot) //
);
});
return gVM;
fml::RefPtr<DartSnapshot> shared_snapshot,
std::shared_ptr<IsolateNameServer> isolate_name_server) {
auto vm_data = DartVMData::Create(settings, //
std::move(vm_snapshot), //
std::move(isolate_snapshot), //
std::move(shared_snapshot) //
);
if (!vm_data) {
FML_LOG(ERROR) << "Could not setup VM data to bootstrap the VM from.";
return {};
}
// Note: std::make_shared unviable due to hidden constructor.
return std::shared_ptr<DartVM>(
new DartVM(std::move(vm_data), std::move(isolate_name_server)));
}
fml::RefPtr<DartVM> DartVM::ForProcessIfInitialized() {
std::lock_guard<std::mutex> lock(gVMMutex);
return gVM;
static std::atomic_size_t gVMLaunchCount;
size_t DartVM::GetVMLaunchCount() {
return gVMLaunchCount;
}
DartVM::DartVM(const Settings& settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot)
: settings_(settings),
vm_snapshot_(std::move(vm_snapshot)),
isolate_snapshot_(std::move(isolate_snapshot)),
shared_snapshot_(std::move(shared_snapshot)),
weak_factory_(this) {
DartVM::DartVM(std::shared_ptr<const DartVMData> vm_data,
std::shared_ptr<IsolateNameServer> isolate_name_server)
: settings_(vm_data->GetSettings()),
vm_data_(vm_data),
isolate_name_server_(std::move(isolate_name_server)),
service_protocol_(std::make_shared<ServiceProtocol>()) {
TRACE_EVENT0("flutter", "DartVMInitializer");
gVMLaunchCount++;
FML_DCHECK(vm_data_);
FML_DCHECK(isolate_name_server_);
FML_DCHECK(service_protocol_);
FML_DLOG(INFO) << "Attempting Dart VM launch for mode: "
<< (IsRunningPrecompiledCode() ? "AOT" : "Interpreter");
@@ -306,8 +289,8 @@ DartVM::DartVM(const Settings& settings,
TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo");
dart::bin::BootstrapDartIo();
if (!settings.temp_directory_path.empty()) {
dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str());
if (!settings_.temp_directory_path.empty()) {
dart::bin::SetSystemTempDirectory(settings_.temp_directory_path.c_str());
}
}
@@ -320,7 +303,7 @@ DartVM::DartVM(const Settings& settings,
args.push_back("--ignore-unrecognized-flags");
for (auto* const profiler_flag :
ProfilingFlags(settings.enable_dart_profiling)) {
ProfilingFlags(settings_.enable_dart_profiling)) {
args.push_back(profiler_flag);
}
@@ -333,7 +316,7 @@ DartVM::DartVM(const Settings& settings,
// Enable Dart assertions if we are not running precompiled code. We run non-
// precompiled code only in the debug product mode.
bool enable_asserts = !settings.disable_dart_asserts;
bool enable_asserts = !settings_.disable_dart_asserts;
#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DYNAMIC_PROFILE || \
FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DYNAMIC_RELEASE
@@ -357,24 +340,24 @@ DartVM::DartVM(const Settings& settings,
PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs));
}
if (settings.start_paused) {
if (settings_.start_paused) {
PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs));
}
if (settings.endless_trace_buffer || settings.trace_startup) {
if (settings_.endless_trace_buffer || settings_.trace_startup) {
// If we are tracing startup, make sure the trace buffer is endless so we
// don't lose early traces.
PushBackAll(&args, kDartEndlessTraceBufferArgs,
arraysize(kDartEndlessTraceBufferArgs));
}
if (settings.trace_systrace) {
if (settings_.trace_systrace) {
PushBackAll(&args, kDartSystraceTraceBufferArgs,
arraysize(kDartSystraceTraceBufferArgs));
PushBackAll(&args, kDartTraceStreamsArgs, arraysize(kDartTraceStreamsArgs));
}
if (settings.trace_startup) {
if (settings_.trace_startup) {
PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs));
}
@@ -383,8 +366,8 @@ DartVM::DartVM(const Settings& settings,
PushBackAll(&args, kDartTraceStreamsArgs, arraysize(kDartTraceStreamsArgs));
#endif
for (size_t i = 0; i < settings.dart_flags.size(); i++)
args.push_back(settings.dart_flags[i].c_str());
for (size_t i = 0; i < settings_.dart_flags.size(); i++)
args.push_back(settings_.dart_flags[i].c_str());
char* flags_error = Dart_SetVMFlags(args.size(), args.data());
if (flags_error) {
@@ -394,14 +377,14 @@ DartVM::DartVM(const Settings& settings,
DartUI::InitForGlobal();
Dart_SetFileModifiedCallback(&DartFileModifiedCallback);
{
TRACE_EVENT0("flutter", "Dart_Initialize");
Dart_InitializeParams params = {};
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
params.vm_snapshot_data = vm_snapshot_->GetData()->GetSnapshotPointer();
params.vm_snapshot_instructions = vm_snapshot_->GetInstructionsIfPresent();
params.vm_snapshot_data =
vm_data_->GetVMSnapshot().GetData()->GetSnapshotPointer();
params.vm_snapshot_instructions =
vm_data_->GetVMSnapshot().GetInstructionsIfPresent();
params.create = reinterpret_cast<decltype(params.create)>(
DartIsolate::DartIsolateCreateCallback);
params.shutdown = reinterpret_cast<decltype(params.shutdown)>(
@@ -433,51 +416,50 @@ DartVM::DartVM(const Settings& settings,
}
}
Dart_SetFileModifiedCallback(&DartFileModifiedCallback);
// Allow streaming of stdout and stderr by the Dart vm.
Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback,
&ServiceStreamCancelCallback);
Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback);
FML_DLOG(INFO) << "New Dart VM instance created. Instance count: "
<< gVMLaunchCount;
}
DartVM::~DartVM() {
if (Dart_CurrentIsolate() != nullptr) {
Dart_ExitIsolate();
}
char* result = Dart_Cleanup();
if (result != nullptr) {
FML_LOG(ERROR) << "Could not cleanly shut down the Dart VM. Message: \""
<< result << "\".";
free(result);
}
dart::bin::CleanupDartIo();
FML_CHECK(result == nullptr)
<< "Could not cleanly shut down the Dart VM. Error: \"" << result
<< "\".";
free(result);
FML_DLOG(INFO) << "Dart VM instance destroyed. Instance count: "
<< gVMLaunchCount;
}
std::shared_ptr<const DartVMData> DartVM::GetVMData() const {
return vm_data_;
}
const Settings& DartVM::GetSettings() const {
return settings_;
}
const DartSnapshot& DartVM::GetVMSnapshot() const {
return *vm_snapshot_.get();
}
IsolateNameServer* DartVM::GetIsolateNameServer() {
return &isolate_name_server_;
}
fml::RefPtr<DartSnapshot> DartVM::GetIsolateSnapshot() const {
return isolate_snapshot_;
}
fml::RefPtr<DartSnapshot> DartVM::GetSharedSnapshot() const {
return shared_snapshot_;
}
ServiceProtocol& DartVM::GetServiceProtocol() {
std::shared_ptr<ServiceProtocol> DartVM::GetServiceProtocol() const {
return service_protocol_;
}
fml::WeakPtr<DartVM> DartVM::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
std::shared_ptr<IsolateNameServer> DartVM::GetIsolateNameServer() const {
return isolate_name_server_;
}
} // namespace blink

View File

@@ -5,9 +5,8 @@
#ifndef FLUTTER_RUNTIME_DART_VM_H_
#define FLUTTER_RUNTIME_DART_VM_H_
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "flutter/common/settings.h"
#include "flutter/fml/build_config.h"
@@ -19,59 +18,48 @@
#include "flutter/lib/ui/isolate_name_server/isolate_name_server.h"
#include "flutter/runtime/dart_isolate.h"
#include "flutter/runtime/dart_snapshot.h"
#include "flutter/runtime/dart_vm_data.h"
#include "flutter/runtime/service_protocol.h"
#include "third_party/dart/runtime/include/dart_api.h"
namespace blink {
class DartVM : public fml::RefCountedThreadSafe<DartVM> {
class DartVM {
public:
static fml::RefPtr<DartVM> ForProcess(Settings settings);
static fml::RefPtr<DartVM> ForProcess(
Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot);
static fml::RefPtr<DartVM> ForProcessIfInitialized();
~DartVM();
static bool IsRunningPrecompiledCode();
static bool IsKernelMapping(const fml::FileMapping* mapping);
static size_t GetVMLaunchCount();
const Settings& GetSettings() const;
const DartSnapshot& GetVMSnapshot() const;
std::shared_ptr<const DartVMData> GetVMData() const;
IsolateNameServer* GetIsolateNameServer();
std::shared_ptr<ServiceProtocol> GetServiceProtocol() const;
fml::RefPtr<DartSnapshot> GetIsolateSnapshot() const;
fml::RefPtr<DartSnapshot> GetSharedSnapshot() const;
fml::WeakPtr<DartVM> GetWeakPtr();
ServiceProtocol& GetServiceProtocol();
std::shared_ptr<IsolateNameServer> GetIsolateNameServer() const;
private:
const Settings settings_;
const fml::RefPtr<DartSnapshot> vm_snapshot_;
IsolateNameServer isolate_name_server_;
const fml::RefPtr<DartSnapshot> isolate_snapshot_;
const fml::RefPtr<DartSnapshot> shared_snapshot_;
ServiceProtocol service_protocol_;
fml::WeakPtrFactory<DartVM> weak_factory_;
std::shared_ptr<const DartVMData> vm_data_;
const std::shared_ptr<IsolateNameServer> isolate_name_server_;
const std::shared_ptr<ServiceProtocol> service_protocol_;
DartVM(const Settings& settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot);
friend class DartVMRef;
~DartVM();
static std::shared_ptr<DartVM> Create(
Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
std::shared_ptr<IsolateNameServer> isolate_name_server);
DartVM(std::shared_ptr<const DartVMData> data,
std::shared_ptr<IsolateNameServer> isolate_name_server);
FML_FRIEND_REF_COUNTED_THREAD_SAFE(DartVM);
FML_FRIEND_MAKE_REF_COUNTED(DartVM);
FML_DISALLOW_COPY_AND_ASSIGN(DartVM);
};

View File

@@ -0,0 +1,79 @@
// 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/dart_vm_data.h"
namespace blink {
std::shared_ptr<const DartVMData> DartVMData::Create(
Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot) {
if (!vm_snapshot || !vm_snapshot->IsValid()) {
// Caller did not provide a valid VM snapshot. Attempt to infer one
// from the settings.
vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings);
if (!vm_snapshot) {
FML_LOG(ERROR)
<< "VM snapshot invalid and could not be inferred from settings.";
return {};
}
}
if (!isolate_snapshot || !isolate_snapshot->IsValid()) {
// Caller did not provide a valid isolate snapshot. Attempt to infer one
// from the settings.
isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings);
if (!isolate_snapshot) {
FML_LOG(ERROR) << "Isolate snapshot invalid and could not be inferred "
"from settings.";
return {};
}
}
if (!shared_snapshot || !shared_snapshot->IsValid()) {
shared_snapshot = DartSnapshot::Empty();
if (!shared_snapshot) {
FML_LOG(ERROR) << "Shared snapshot invalid.";
return {};
}
}
return std::shared_ptr<const DartVMData>(new DartVMData(
std::move(settings), //
std::move(vm_snapshot), //
std::move(isolate_snapshot), //
std::move(shared_snapshot) //
));
}
DartVMData::DartVMData(Settings settings,
fml::RefPtr<const DartSnapshot> vm_snapshot,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot)
: settings_(settings),
vm_snapshot_(vm_snapshot),
isolate_snapshot_(isolate_snapshot),
shared_snapshot_(shared_snapshot) {}
DartVMData::~DartVMData() = default;
const Settings& DartVMData::GetSettings() const {
return settings_;
}
const DartSnapshot& DartVMData::GetVMSnapshot() const {
return *vm_snapshot_;
}
fml::RefPtr<const DartSnapshot> DartVMData::GetIsolateSnapshot() const {
return isolate_snapshot_;
}
fml::RefPtr<const DartSnapshot> DartVMData::GetSharedSnapshot() const {
return shared_snapshot_;
}
} // namespace blink

View File

@@ -0,0 +1,47 @@
// 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.
#ifndef FLUTTER_RUNTIME_DART_VM_DATA_H_
#define FLUTTER_RUNTIME_DART_VM_DATA_H_
#include "flutter/fml/macros.h"
#include "flutter/runtime/dart_snapshot.h"
namespace blink {
class DartVMData {
public:
static std::shared_ptr<const DartVMData> Create(
Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot);
~DartVMData();
const Settings& GetSettings() const;
const DartSnapshot& GetVMSnapshot() const;
fml::RefPtr<const DartSnapshot> GetIsolateSnapshot() const;
fml::RefPtr<const DartSnapshot> GetSharedSnapshot() const;
private:
const Settings settings_;
const fml::RefPtr<const DartSnapshot> vm_snapshot_;
const fml::RefPtr<const DartSnapshot> isolate_snapshot_;
const fml::RefPtr<const DartSnapshot> shared_snapshot_;
DartVMData(Settings settings,
fml::RefPtr<const DartSnapshot> vm_snapshot,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot);
FML_DISALLOW_COPY_AND_ASSIGN(DartVMData);
};
} // namespace blink
#endif // FLUTTER_RUNTIME_DART_VM_DATA_H_

View File

@@ -0,0 +1,112 @@
// 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/dart_vm_lifecycle.h"
#include <mutex>
namespace blink {
// We need to explicitly put the constructor and destructor of the DartVM in the
// critical section. All accesses (not just const members) to the global VM
// object weak pointer are behind this mutex.
static std::mutex gVMMutex;
static std::weak_ptr<DartVM> gVM FML_GUARDED_BY(gVMMutex);
// We are going to be modifying more than just the control blocks of the
// following weak pointers (in the |Create| case where an old VM could not be
// reused). Ideally, we would use |std::atomic<std::weak_ptr<T>>| specialization
// but that is only available since C++20. We don't expect contention on these
// locks so we just use one mutex for all.
static std::mutex gVMDependentsMutex;
static std::weak_ptr<const DartVMData> gVMData
FML_GUARDED_BY(gVMDependentsMutex);
static std::weak_ptr<ServiceProtocol> gVMServiceProtocol
FML_GUARDED_BY(gVMDependentsMutex);
static std::weak_ptr<IsolateNameServer> gVMIsolateNameServer
FML_GUARDED_BY(gVMDependentsMutex);
DartVMRef::DartVMRef(std::shared_ptr<DartVM> vm) : vm_(vm) {}
DartVMRef::DartVMRef(DartVMRef&& other) = default;
DartVMRef::~DartVMRef() {
if (!vm_) {
// If there is no valid VM (possible via a move), there is no way that the
// decrement on the shared pointer can cause a collection. Avoid acquiring
// the lifecycle lock in this case. This is just working around a
// pessimization and not required for correctness.
return;
}
std::lock_guard<std::mutex> lifecycle_lock(gVMMutex);
vm_.reset();
}
DartVMRef DartVMRef::Create(Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot) {
std::lock_guard<std::mutex> lifecycle_lock(gVMMutex);
// If there is already a running VM in the process, grab a strong reference to
// it.
if (auto vm = gVM.lock()) {
FML_DLOG(WARNING) << "Attempted to create a VM in a process where one was "
"already running. Ignoring arguments for current VM "
"create call and reusing the old VM.";
// There was already a running VM in the process,
return DartVMRef{std::move(vm)};
}
std::lock_guard<std::mutex> dependents_lock(gVMDependentsMutex);
gVMData.reset();
gVMServiceProtocol.reset();
gVMIsolateNameServer.reset();
gVM.reset();
// If there is no VM in the process. Initialize one, hold the weak reference
// and pass a strong reference to the caller.
auto isolate_name_server = std::make_shared<IsolateNameServer>();
auto vm = DartVM::Create(std::move(settings), //
std::move(vm_snapshot), //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
isolate_name_server //
);
if (!vm) {
FML_LOG(ERROR) << "Could not create Dart VM instance.";
return {nullptr};
}
gVMData = vm->GetVMData();
gVMServiceProtocol = vm->GetServiceProtocol();
gVMIsolateNameServer = isolate_name_server;
gVM = vm;
return DartVMRef{std::move(vm)};
}
bool DartVMRef::IsInstanceRunning() {
std::lock_guard<std::mutex> lock(gVMMutex);
return !gVM.expired();
}
std::shared_ptr<const DartVMData> DartVMRef::GetVMData() {
std::lock_guard<std::mutex> lock(gVMDependentsMutex);
return gVMData.lock();
}
std::shared_ptr<ServiceProtocol> DartVMRef::GetServiceProtocol() {
std::lock_guard<std::mutex> lock(gVMDependentsMutex);
return gVMServiceProtocol.lock();
}
std::shared_ptr<IsolateNameServer> DartVMRef::GetIsolateNameServer() {
std::lock_guard<std::mutex> lock(gVMDependentsMutex);
return gVMIsolateNameServer.lock();
}
} // namespace blink

View File

@@ -0,0 +1,72 @@
// 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.
#ifndef FLUTTER_RUNTIME_DART_VM_LIFECYCLE_H_
#define FLUTTER_RUNTIME_DART_VM_LIFECYCLE_H_
#include <memory>
#include "flutter/fml/macros.h"
#include "flutter/lib/ui/isolate_name_server/isolate_name_server.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/service_protocol.h"
namespace blink {
// A strong reference to the Dart VM. There can only be one VM running in the
// process at any given time. A reference to the VM may only be obtained via the
// |Create| method. In case there is already a running instance of the VM in the
// process, a strong reference to that VM is obtained and the arguments to the
// |Create| call ignored. If there is no VM already running in the process, a VM
// is initialized in a thread safe manner and returned to the caller. The VM
// will shutdown only when all callers relinquish their references (by
// collecting their instances of this class).
//
// DartVMRef instances may be created on any thread.
class DartVMRef {
public:
FML_WARN_UNUSED_RESULT
static DartVMRef Create(Settings settings,
fml::RefPtr<DartSnapshot> vm_snapshot = nullptr,
fml::RefPtr<DartSnapshot> isolate_snapshot = nullptr,
fml::RefPtr<DartSnapshot> shared_snapshot = nullptr);
DartVMRef(DartVMRef&&);
~DartVMRef();
// This is an inherently racy way to check if a VM instance is running and
// should not be used outside of unit-tests where there is a known threading
// model.
static bool IsInstanceRunning();
static std::shared_ptr<const DartVMData> GetVMData();
static std::shared_ptr<ServiceProtocol> GetServiceProtocol();
static std::shared_ptr<IsolateNameServer> GetIsolateNameServer();
operator bool() const { return static_cast<bool>(vm_); }
DartVM* operator->() {
FML_DCHECK(vm_);
return vm_.get();
}
DartVM* operator&() {
FML_DCHECK(vm_);
return vm_.get();
}
private:
std::shared_ptr<DartVM> vm_;
DartVMRef(std::shared_ptr<DartVM> vm);
FML_DISALLOW_COPY_AND_ASSIGN(DartVMRef);
};
} // namespace blink
#endif // FLUTTER_RUNTIME_DART_VM_LIFECYCLE_H_

View File

@@ -3,25 +3,36 @@
// found in the LICENSE file.
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/testing/testing.h"
#include "flutter/testing/thread_test.h"
#include "gtest/gtest.h"
namespace blink {
TEST(DartVM, SimpleInitialization) {
Settings settings = {};
static Settings GetTestSettings() {
Settings settings;
settings.verbose_logging = true;
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
auto vm = DartVM::ForProcess(settings);
ASSERT_TRUE(vm);
ASSERT_EQ(vm, DartVM::ForProcess(settings));
return settings;
}
TEST(DartVM, SimpleInitialization) {
auto vm1 = DartVMRef::Create(GetTestSettings());
ASSERT_TRUE(vm1);
// Multiple initializations should return the same VM.
auto vm2 = DartVMRef::Create(GetTestSettings());
ASSERT_TRUE(vm2);
ASSERT_EQ(&vm1, &vm2);
ASSERT_FALSE(DartVM::IsRunningPrecompiledCode());
}
TEST(DartVM, SimpleIsolateNameServer) {
Settings settings = {};
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
auto vm = DartVM::ForProcess(settings);
auto vm = DartVMRef::Create(GetTestSettings());
auto ns = vm->GetIsolateNameServer();
ASSERT_EQ(ns->LookupIsolatePortByName("foobar"), ILLEGAL_PORT);
ASSERT_FALSE(ns->RemoveIsolateNameMapping("foobar"));
@@ -31,4 +42,79 @@ TEST(DartVM, SimpleIsolateNameServer) {
ASSERT_TRUE(ns->RemoveIsolateNameMapping("foobar"));
}
TEST(DartVM, CanReinitializeVMOverAndOver) {
size_t vm_launch_count = DartVM::GetVMLaunchCount();
for (size_t i = 0; i < 1000; ++i) {
FML_LOG(INFO) << "Run " << i + 1;
// VM should not already be running.
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
auto vm = DartVMRef::Create(GetTestSettings());
ASSERT_TRUE(vm);
size_t new_vm_launch_count = DartVM::GetVMLaunchCount();
ASSERT_EQ(vm_launch_count + 1, new_vm_launch_count);
vm_launch_count = new_vm_launch_count;
// VM should now be running
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
}
}
using DartVMThreadTest = ::testing::ThreadTest;
TEST_F(DartVMThreadTest, CanRunIsolatesInANewVM) {
for (size_t i = 0; i < 1000; ++i) {
FML_LOG(INFO) << "Run " << i + 1;
size_t vm_launch_count = DartVM::GetVMLaunchCount();
// VM should not already be running.
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
auto vm = DartVMRef::Create(GetTestSettings());
ASSERT_TRUE(vm);
// VM should not already be running.
ASSERT_TRUE(DartVMRef::IsInstanceRunning());
size_t new_vm_launch_count = DartVM::GetVMLaunchCount();
ASSERT_EQ(vm_launch_count + 1, new_vm_launch_count);
Settings settings = {};
settings.task_observer_add = [](intptr_t, fml::closure) {};
settings.task_observer_remove = [](intptr_t) {};
auto labels = testing::GetCurrentTestName() + std::to_string(i);
shell::ThreadHost host(labels, shell::ThreadHost::Type::UI |
shell::ThreadHost::Type::GPU |
shell::ThreadHost::Type::IO);
TaskRunners task_runners(
labels, // task runner labels
GetCurrentTaskRunner(), // platform task runner
host.gpu_thread->GetTaskRunner(), // GPU task runner
host.ui_thread->GetTaskRunner(), // UI task runner
host.io_thread->GetTaskRunner() // IO task runner
);
auto weak_isolate = DartIsolate::CreateRootIsolate(
vm->GetVMData()->GetSettings(), // settings
vm->GetVMData()->GetIsolateSnapshot(), // isolate snapshot
vm->GetVMData()->GetSharedSnapshot(), // shared snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
);
auto root_isolate = weak_isolate.lock();
ASSERT_TRUE(root_isolate);
ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup);
ASSERT_TRUE(root_isolate->Shutdown());
}
}
} // namespace blink

View File

@@ -17,8 +17,8 @@ namespace blink {
RuntimeController::RuntimeController(
RuntimeDelegate& p_client,
DartVM* p_vm,
fml::RefPtr<DartSnapshot> p_isolate_snapshot,
fml::RefPtr<DartSnapshot> p_shared_snapshot,
fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
fml::RefPtr<const DartSnapshot> p_shared_snapshot,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<IOManager> p_io_manager,
@@ -40,8 +40,8 @@ RuntimeController::RuntimeController(
RuntimeController::RuntimeController(
RuntimeDelegate& p_client,
DartVM* p_vm,
fml::RefPtr<DartSnapshot> p_isolate_snapshot,
fml::RefPtr<DartSnapshot> p_shared_snapshot,
fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
fml::RefPtr<const DartSnapshot> p_shared_snapshot,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<IOManager> p_io_manager,
@@ -61,7 +61,7 @@ RuntimeController::RuntimeController(
idle_notification_callback_(idle_notification_callback),
window_data_(std::move(p_window_data)),
root_isolate_(
DartIsolate::CreateRootIsolate(vm_,
DartIsolate::CreateRootIsolate(vm_->GetVMData()->GetSettings(),
isolate_snapshot_,
shared_snapshot_,
task_runners_,

View File

@@ -30,8 +30,8 @@ class RuntimeController final : public WindowClient {
public:
RuntimeController(RuntimeDelegate& client,
DartVM* vm,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
@@ -118,8 +118,8 @@ class RuntimeController final : public WindowClient {
RuntimeDelegate& client_;
DartVM* const vm_;
fml::RefPtr<DartSnapshot> isolate_snapshot_;
fml::RefPtr<DartSnapshot> shared_snapshot_;
fml::RefPtr<const DartSnapshot> isolate_snapshot_;
fml::RefPtr<const DartSnapshot> shared_snapshot_;
TaskRunners task_runners_;
fml::WeakPtr<SnapshotDelegate> snapshot_delegate_;
fml::WeakPtr<IOManager> io_manager_;
@@ -132,8 +132,8 @@ class RuntimeController final : public WindowClient {
RuntimeController(RuntimeDelegate& client,
DartVM* vm,
fml::RefPtr<DartSnapshot> isolate_snapshot,
fml::RefPtr<DartSnapshot> shared_snapshot,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
fml::RefPtr<const DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,

View File

@@ -37,8 +37,8 @@ static constexpr char kSettingsChannel[] = "flutter/settings";
Engine::Engine(Delegate& delegate,
blink::DartVM& vm,
fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<blink::DartSnapshot> shared_snapshot,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
blink::TaskRunners task_runners,
blink::Settings settings,
std::unique_ptr<Animator> animator,

View File

@@ -56,8 +56,8 @@ class Engine final : public blink::RuntimeDelegate {
Engine(Delegate& delegate,
blink::DartVM& vm,
fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<blink::DartSnapshot> shared_snapshot,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
blink::TaskRunners task_runners,
blink::Settings settings,
std::unique_ptr<Animator> animator,

View File

@@ -36,17 +36,20 @@ namespace shell {
constexpr char kSkiaChannel[] = "flutter/skia";
std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
blink::DartVMRef vm,
blink::TaskRunners task_runners,
blink::Settings settings,
fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<blink::DartSnapshot> shared_snapshot,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
if (!task_runners.IsValid()) {
FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
return nullptr;
}
auto shell = std::unique_ptr<Shell>(new Shell(task_runners, settings));
auto shell =
std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
// Create the platform view on the platform thread (this thread).
auto platform_view = on_create_platform_view(*shell.get());
@@ -75,6 +78,7 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
&platform_view, //
io_task_runner //
]() {
TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
io_manager = std::make_unique<IOManager>(
platform_view->CreateResourceContext(), io_task_runner);
io_latch.Signal();
@@ -92,6 +96,7 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
shell = shell.get(), //
&snapshot_delegate //
]() {
TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
if (auto new_rasterizer = on_create_rasterizer(*shell)) {
rasterizer = std::move(new_rasterizer);
snapshot_delegate = rasterizer->GetSnapshotDelegate();
@@ -115,6 +120,7 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
snapshot_delegate = std::move(snapshot_delegate), //
io_manager = io_manager->GetWeakPtr() //
]() mutable {
TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
const auto& task_runners = shell->GetTaskRunners();
// The animator is owned by the UI thread but it gets its vsync pulses
@@ -123,7 +129,7 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
std::move(vsync_waiter));
engine = std::make_unique<Engine>(*shell, //
shell->GetDartVM(), //
*shell->GetDartVM(), //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
task_runners, //
@@ -204,26 +210,35 @@ std::unique_ptr<Shell> Shell::Create(
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
PerformInitializationTasks(settings);
auto vm = blink::DartVM::ForProcess(settings);
TRACE_EVENT0("flutter", "Shell::Create");
auto vm = blink::DartVMRef::Create(settings);
FML_CHECK(vm) << "Must be able to initialize the VM.";
auto vm_data = vm->GetVMData();
return Shell::Create(std::move(task_runners), //
std::move(settings), //
vm->GetIsolateSnapshot(), //
blink::DartSnapshot::Empty(), //
vm_data->GetIsolateSnapshot(), // isolate snapshot
blink::DartSnapshot::Empty(), // shared snapshot
std::move(on_create_platform_view), //
std::move(on_create_rasterizer) //
std::move(on_create_rasterizer), //
std::move(vm) //
);
}
std::unique_ptr<Shell> Shell::Create(
blink::TaskRunners task_runners,
blink::Settings settings,
fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<blink::DartSnapshot> shared_snapshot,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
Shell::CreateCallback<Rasterizer> on_create_rasterizer,
blink::DartVMRef vm) {
PerformInitializationTasks(settings);
TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
if (!task_runners.IsValid() || !on_create_platform_view ||
!on_create_rasterizer) {
return nullptr;
@@ -233,16 +248,18 @@ std::unique_ptr<Shell> Shell::Create(
std::unique_ptr<Shell> shell;
fml::TaskRunner::RunNowOrPostTask(
task_runners.GetPlatformTaskRunner(),
[&latch, //
&shell, //
task_runners = std::move(task_runners), //
settings, //
isolate_snapshot = std::move(isolate_snapshot), //
shared_snapshot = std::move(shared_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
]() {
shell = CreateShellOnPlatformThread(std::move(task_runners), //
fml::MakeCopyable([&latch, //
vm = std::move(vm), //
&shell, //
task_runners = std::move(task_runners), //
settings, //
isolate_snapshot = std::move(isolate_snapshot), //
shared_snapshot = std::move(shared_snapshot), //
on_create_platform_view, //
on_create_rasterizer //
]() mutable {
shell = CreateShellOnPlatformThread(std::move(vm),
std::move(task_runners), //
settings, //
std::move(isolate_snapshot), //
std::move(shared_snapshot), //
@@ -250,15 +267,18 @@ std::unique_ptr<Shell> Shell::Create(
on_create_rasterizer //
);
latch.Signal();
});
}));
latch.Wait();
return shell;
}
Shell::Shell(blink::TaskRunners task_runners, blink::Settings settings)
Shell::Shell(blink::DartVMRef vm,
blink::TaskRunners task_runners,
blink::Settings settings)
: task_runners_(std::move(task_runners)),
settings_(std::move(settings)),
vm_(blink::DartVM::ForProcess(settings_)) {
vm_(std::move(vm)) {
FML_CHECK(vm_) << "Must have access to VM to create a shell.";
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
@@ -300,9 +320,7 @@ Shell::~Shell() {
PersistentCache::GetCacheForProcess()->RemoveWorkerTaskRunner(
task_runners_.GetIOTaskRunner());
if (auto vm = blink::DartVM::ForProcessIfInitialized()) {
vm->GetServiceProtocol().RemoveHandler(this);
}
vm_->GetServiceProtocol()->RemoveHandler(this);
fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;
@@ -373,9 +391,7 @@ bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
is_setup_ = true;
if (auto vm = blink::DartVM::ForProcessIfInitialized()) {
vm->GetServiceProtocol().AddHandler(this, GetServiceProtocolDescription());
}
vm_->GetServiceProtocol()->AddHandler(this, GetServiceProtocolDescription());
PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(
task_runners_.GetIOTaskRunner());
@@ -406,12 +422,13 @@ fml::WeakPtr<PlatformView> Shell::GetPlatformView() {
return platform_view_->GetWeakPtr();
}
blink::DartVM& Shell::GetDartVM() const {
return *vm_;
blink::DartVM* Shell::GetDartVM() {
return &vm_;
}
// |shell::PlatformView::Delegate|
void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
@@ -469,6 +486,7 @@ void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
// |shell::PlatformView::Delegate|
void Shell::OnPlatformViewDestroyed() {
TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
@@ -804,10 +822,8 @@ void Shell::OnPreEngineRestart() {
// |shell::Engine::Delegate|
void Shell::UpdateIsolateDescription(const std::string isolate_name,
int64_t isolate_port) {
if (auto vm = blink::DartVM::ForProcessIfInitialized()) {
Handler::Description description(isolate_port, isolate_name);
vm->GetServiceProtocol().SetHandlerDescription(this, description);
}
Handler::Description description(isolate_port, isolate_name);
vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
}
// |blink::ServiceProtocol::Handler|

View File

@@ -23,6 +23,7 @@
#include "flutter/lib/ui/semantics/custom_accessibility_action.h"
#include "flutter/lib/ui/semantics/semantics_node.h"
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/runtime/service_protocol.h"
#include "flutter/shell/common/animator.h"
#include "flutter/shell/common/engine.h"
@@ -54,10 +55,11 @@ class Shell final : public PlatformView::Delegate,
static std::unique_ptr<Shell> Create(
blink::TaskRunners task_runners,
blink::Settings settings,
fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<blink::DartSnapshot> shared_snapshot,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
CreateCallback<PlatformView> on_create_platform_view,
CreateCallback<Rasterizer> on_create_rasterizer);
CreateCallback<Rasterizer> on_create_rasterizer,
blink::DartVMRef vm);
~Shell();
@@ -71,7 +73,7 @@ class Shell final : public PlatformView::Delegate,
fml::WeakPtr<PlatformView> GetPlatformView();
blink::DartVM& GetDartVM() const;
blink::DartVM* GetDartVM();
bool IsSetup() const;
@@ -85,7 +87,7 @@ class Shell final : public PlatformView::Delegate,
const blink::TaskRunners task_runners_;
const blink::Settings settings_;
fml::RefPtr<blink::DartVM> vm_;
blink::DartVMRef vm_;
std::unique_ptr<PlatformView> platform_view_; // on platform task runner
std::unique_ptr<Engine> engine_; // on UI task runner
std::unique_ptr<Rasterizer> rasterizer_; // on GPU task runner
@@ -98,16 +100,19 @@ class Shell final : public PlatformView::Delegate,
>
service_protocol_handlers_;
bool is_setup_ = false;
uint64_t next_pointer_flow_id_ = 0;
Shell(blink::TaskRunners task_runners, blink::Settings settings);
Shell(blink::DartVMRef vm,
blink::TaskRunners task_runners,
blink::Settings settings);
static std::unique_ptr<Shell> CreateShellOnPlatformThread(
blink::DartVMRef vm,
blink::TaskRunners task_runners,
blink::Settings settings,
fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<blink::DartSnapshot> shared_snapshot,
fml::RefPtr<const blink::DartSnapshot> isolate_snapshot,
fml::RefPtr<const blink::DartSnapshot> shared_snapshot,
Shell::CreateCallback<PlatformView> on_create_platform_view,
Shell::CreateCallback<Rasterizer> on_create_rasterizer);

View File

@@ -6,6 +6,8 @@
namespace testing {
//
std::string GetCurrentTestName() {
return UnitTest::GetInstance()->current_test_info()->name();
}
} // namespace testing

View File

@@ -5,6 +5,8 @@
#ifndef TESTING_TESTING_H_
#define TESTING_TESTING_H_
#include <string>
#include "gtest/gtest.h"
namespace testing {
@@ -14,6 +16,8 @@ namespace testing {
// error.
const char* GetFixturesPath();
std::string GetCurrentTestName();
} // namespace testing
#endif // TESTING_TESTING_H_