#include "flutter/runtime/dart_vm_lifecycle.h"
#include <mutex>
namespace flutter {
static std::mutex gVMMutex;
static std::weak_ptr<DartVM> gVM FML_GUARDED_BY(gVMMutex);
static std::shared_ptr<DartVM>* gVMLeak FML_GUARDED_BY(gVMMutex);
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_) {
return;
}
std::scoped_lock 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::scoped_lock lifecycle_lock(gVMMutex);
if (!settings.leak_vm) {
FML_CHECK(!gVMLeak)
<< "Launch settings indicated that the VM should shut down in the "
"process when done but a previous launch asked the VM to leak in "
"the same process. For proper VM shutdown, all VM launches must "
"indicate that they should shut down when done.";
}
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.";
return DartVMRef{std::move(vm)};
}
std::scoped_lock dependents_lock(gVMDependentsMutex);
gVMData.reset();
gVMServiceProtocol.reset();
gVMIsolateNameServer.reset();
gVM.reset();
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;
if (settings.leak_vm) {
gVMLeak = new std::shared_ptr<DartVM>(vm);
}
return DartVMRef{std::move(vm)};
}
bool DartVMRef::IsInstanceRunning() {
std::scoped_lock lock(gVMMutex);
return !gVM.expired();
}
std::shared_ptr<const DartVMData> DartVMRef::GetVMData() {
std::scoped_lock lock(gVMDependentsMutex);
return gVMData.lock();
}
std::shared_ptr<ServiceProtocol> DartVMRef::GetServiceProtocol() {
std::scoped_lock lock(gVMDependentsMutex);
return gVMServiceProtocol.lock();
}
std::shared_ptr<IsolateNameServer> DartVMRef::GetIsolateNameServer() {
std::scoped_lock lock(gVMDependentsMutex);
return gVMIsolateNameServer.lock();
}
DartVM* DartVMRef::GetRunningVM() {
std::scoped_lock lock(gVMMutex);
auto vm = gVM.lock().get();
FML_CHECK(vm) << "Caller assumed VM would be running when it wasn't";
return vm;
}
}