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/common/task_runners.h"
6 #include "flutter/fml/paths.h"
7 #include "flutter/fml/synchronization/count_down_latch.h"
8 #include "flutter/fml/synchronization/waitable_event.h"
9 #include "flutter/runtime/dart_vm.h"
10 #include "flutter/runtime/dart_vm_lifecycle.h"
11 #include "flutter/runtime/runtime_test.h"
12
13 namespace flutter {
14 namespace testing {
15
16 using DartLifecycleTest = RuntimeTest;
17
TEST_F(DartLifecycleTest,CanStartAndShutdownVM)18 TEST_F(DartLifecycleTest, CanStartAndShutdownVM) {
19 auto settings = CreateSettingsForFixture();
20 settings.leak_vm = false;
21 settings.enable_observatory = false;
22 ASSERT_FALSE(DartVMRef::IsInstanceRunning());
23 {
24 auto vm_ref = DartVMRef::Create(settings);
25 ASSERT_TRUE(DartVMRef::IsInstanceRunning());
26 }
27 ASSERT_FALSE(DartVMRef::IsInstanceRunning());
28 }
29
TEST_F(DartLifecycleTest,CanStartAndShutdownVMOverAndOver)30 TEST_F(DartLifecycleTest, CanStartAndShutdownVMOverAndOver) {
31 auto settings = CreateSettingsForFixture();
32 settings.leak_vm = false;
33 settings.enable_observatory = false;
34 ASSERT_FALSE(DartVMRef::IsInstanceRunning());
35 auto count = DartVM::GetVMLaunchCount();
36 for (size_t i = 0; i < 10; i++) {
37 auto vm_ref = DartVMRef::Create(settings);
38 ASSERT_TRUE(DartVMRef::IsInstanceRunning());
39 ASSERT_EQ(DartVM::GetVMLaunchCount(), count + 1);
40 count = DartVM::GetVMLaunchCount();
41 }
42 ASSERT_FALSE(DartVMRef::IsInstanceRunning());
43 }
44
CreateAndRunRootIsolate(const Settings & settings,const DartVMData & vm,fml::RefPtr<fml::TaskRunner> task_runner,std::string entrypoint)45 static std::shared_ptr<DartIsolate> CreateAndRunRootIsolate(
46 const Settings& settings,
47 const DartVMData& vm,
48 fml::RefPtr<fml::TaskRunner> task_runner,
49 std::string entrypoint) {
50 FML_CHECK(entrypoint.size() > 0);
51 TaskRunners runners("io.flutter.test", task_runner, task_runner, task_runner,
52 task_runner);
53 auto isolate_weak = DartIsolate::CreateRootIsolate(
54 vm.GetSettings(), // settings
55 vm.GetIsolateSnapshot(), // isolate_snapshot
56 vm.GetSharedSnapshot(), // shared_snapshot
57 runners, // task_runners
58 {}, // window
59 {}, // io_manager
60 {}, // image_decoder
61 "main.dart", // advisory_script_uri
62 entrypoint.c_str(), // advisory_script_entrypoint
63 nullptr, // flags
64 settings.isolate_create_callback, // isolate create callback
65 settings.isolate_shutdown_callback // isolate shutdown callback
66 );
67
68 auto isolate = isolate_weak.lock();
69
70 if (!isolate) {
71 FML_LOG(ERROR) << "Could not create valid isolate.";
72 return nullptr;
73 }
74
75 if (DartVM::IsRunningPrecompiledCode()) {
76 if (!isolate->PrepareForRunningFromPrecompiledCode()) {
77 FML_LOG(ERROR)
78 << "Could not prepare to run the isolate from precompiled code.";
79 return nullptr;
80 }
81
82 } else {
83 if (!isolate->PrepareForRunningFromKernels(
84 settings.application_kernels())) {
85 FML_LOG(ERROR) << "Could not prepare isolate from application kernels.";
86 return nullptr;
87 }
88 }
89
90 if (isolate->GetPhase() != DartIsolate::Phase::Ready) {
91 FML_LOG(ERROR) << "Isolate was not ready.";
92 return nullptr;
93 }
94
95 if (!isolate->Run(entrypoint, {}, settings.root_isolate_create_callback)) {
96 FML_LOG(ERROR) << "Could not run entrypoint: " << entrypoint << ".";
97 return nullptr;
98 }
99
100 if (isolate->GetPhase() != DartIsolate::Phase::Running) {
101 FML_LOG(ERROR) << "Isolate was not Running.";
102 return nullptr;
103 }
104
105 return isolate;
106 }
107
108 // TODO(chinmaygarde): This unit-test is flaky and indicates thread un-safety
109 // during shutdown. https://github.com/flutter/flutter/issues/36782
TEST_F(DartLifecycleTest,DISABLED_ShuttingDownTheVMShutsDownAllIsolates)110 TEST_F(DartLifecycleTest, DISABLED_ShuttingDownTheVMShutsDownAllIsolates) {
111 auto settings = CreateSettingsForFixture();
112 settings.leak_vm = false;
113 // Make sure the service protocol launches
114 settings.enable_observatory = true;
115
116 for (size_t i = 0; i < 3; i++) {
117 ASSERT_FALSE(DartVMRef::IsInstanceRunning());
118
119 const auto last_launch_count = DartVM::GetVMLaunchCount();
120
121 auto vm_ref = DartVMRef::Create(settings);
122
123 ASSERT_TRUE(DartVMRef::IsInstanceRunning());
124 ASSERT_EQ(last_launch_count + 1, DartVM::GetVMLaunchCount());
125
126 const size_t isolate_count = 5;
127
128 fml::CountDownLatch latch(isolate_count);
129 auto vm_data = vm_ref.GetVMData();
130 auto thread_task_runner = GetThreadTaskRunner();
131 for (size_t i = 0; i < isolate_count; ++i) {
132 thread_task_runner->PostTask(
133 [vm_data, &settings, &latch, thread_task_runner]() {
134 ASSERT_TRUE(CreateAndRunRootIsolate(settings, *vm_data.get(),
135 thread_task_runner,
136 "testIsolateShutdown"));
137 latch.CountDown();
138 });
139 }
140
141 latch.Wait();
142 }
143 ASSERT_FALSE(DartVMRef::IsInstanceRunning());
144 }
145
146 } // namespace testing
147 } // namespace flutter
148