• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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