1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/runtime/dart_vm_lifecycle.h"
6
7 #include <mutex>
8
9 namespace flutter {
10
11 // We need to explicitly put the constructor and destructor of the DartVM in the
12 // critical section. All accesses (not just const members) to the global VM
13 // object weak pointer are behind this mutex.
14 static std::mutex gVMMutex;
15 static std::weak_ptr<DartVM> gVM FML_GUARDED_BY(gVMMutex);
16 static std::shared_ptr<DartVM>* gVMLeak FML_GUARDED_BY(gVMMutex);
17
18 // We are going to be modifying more than just the control blocks of the
19 // following weak pointers (in the |Create| case where an old VM could not be
20 // reused). Ideally, we would use |std::atomic<std::weak_ptr<T>>| specialization
21 // but that is only available since C++20. We don't expect contention on these
22 // locks so we just use one mutex for all.
23 static std::mutex gVMDependentsMutex;
24 static std::weak_ptr<const DartVMData> gVMData
25 FML_GUARDED_BY(gVMDependentsMutex);
26 static std::weak_ptr<ServiceProtocol> gVMServiceProtocol
27 FML_GUARDED_BY(gVMDependentsMutex);
28 static std::weak_ptr<IsolateNameServer> gVMIsolateNameServer
29 FML_GUARDED_BY(gVMDependentsMutex);
30
DartVMRef(std::shared_ptr<DartVM> vm)31 DartVMRef::DartVMRef(std::shared_ptr<DartVM> vm) : vm_(vm) {}
32
33 DartVMRef::DartVMRef(DartVMRef&& other) = default;
34
~DartVMRef()35 DartVMRef::~DartVMRef() {
36 if (!vm_) {
37 // If there is no valid VM (possible via a move), there is no way that the
38 // decrement on the shared pointer can cause a collection. Avoid acquiring
39 // the lifecycle lock in this case. This is just working around a
40 // pessimization and not required for correctness.
41 return;
42 }
43 std::scoped_lock lifecycle_lock(gVMMutex);
44 vm_.reset();
45 }
46
Create(Settings settings,fml::RefPtr<DartSnapshot> vm_snapshot,fml::RefPtr<DartSnapshot> isolate_snapshot,fml::RefPtr<DartSnapshot> shared_snapshot)47 DartVMRef DartVMRef::Create(Settings settings,
48 fml::RefPtr<DartSnapshot> vm_snapshot,
49 fml::RefPtr<DartSnapshot> isolate_snapshot,
50 fml::RefPtr<DartSnapshot> shared_snapshot) {
51 std::scoped_lock lifecycle_lock(gVMMutex);
52
53 if (!settings.leak_vm) {
54 FML_CHECK(!gVMLeak)
55 << "Launch settings indicated that the VM should shut down in the "
56 "process when done but a previous launch asked the VM to leak in "
57 "the same process. For proper VM shutdown, all VM launches must "
58 "indicate that they should shut down when done.";
59 }
60
61 // If there is already a running VM in the process, grab a strong reference to
62 // it.
63 if (auto vm = gVM.lock()) {
64 FML_DLOG(WARNING) << "Attempted to create a VM in a process where one was "
65 "already running. Ignoring arguments for current VM "
66 "create call and reusing the old VM.";
67 // There was already a running VM in the process,
68 return DartVMRef{std::move(vm)};
69 }
70
71 std::scoped_lock dependents_lock(gVMDependentsMutex);
72
73 gVMData.reset();
74 gVMServiceProtocol.reset();
75 gVMIsolateNameServer.reset();
76 gVM.reset();
77
78 // If there is no VM in the process. Initialize one, hold the weak reference
79 // and pass a strong reference to the caller.
80 auto isolate_name_server = std::make_shared<IsolateNameServer>();
81 auto vm = DartVM::Create(std::move(settings), //
82 std::move(vm_snapshot), //
83 std::move(isolate_snapshot), //
84 std::move(shared_snapshot), //
85 isolate_name_server //
86 );
87
88 if (!vm) {
89 FML_LOG(ERROR) << "Could not create Dart VM instance.";
90 return {nullptr};
91 }
92
93 gVMData = vm->GetVMData();
94 gVMServiceProtocol = vm->GetServiceProtocol();
95 gVMIsolateNameServer = isolate_name_server;
96 gVM = vm;
97
98 if (settings.leak_vm) {
99 gVMLeak = new std::shared_ptr<DartVM>(vm);
100 }
101
102 return DartVMRef{std::move(vm)};
103 }
104
IsInstanceRunning()105 bool DartVMRef::IsInstanceRunning() {
106 std::scoped_lock lock(gVMMutex);
107 return !gVM.expired();
108 }
109
GetVMData()110 std::shared_ptr<const DartVMData> DartVMRef::GetVMData() {
111 std::scoped_lock lock(gVMDependentsMutex);
112 return gVMData.lock();
113 }
114
GetServiceProtocol()115 std::shared_ptr<ServiceProtocol> DartVMRef::GetServiceProtocol() {
116 std::scoped_lock lock(gVMDependentsMutex);
117 return gVMServiceProtocol.lock();
118 }
119
GetIsolateNameServer()120 std::shared_ptr<IsolateNameServer> DartVMRef::GetIsolateNameServer() {
121 std::scoped_lock lock(gVMDependentsMutex);
122 return gVMIsolateNameServer.lock();
123 }
124
GetRunningVM()125 DartVM* DartVMRef::GetRunningVM() {
126 std::scoped_lock lock(gVMMutex);
127 auto vm = gVM.lock().get();
128 FML_CHECK(vm) << "Caller assumed VM would be running when it wasn't";
129 return vm;
130 }
131
132 } // namespace flutter
133