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/testing/fixture_test.h" |
12 | |
13 | namespace flutter { |
14 | namespace testing { |
15 | |
16 | using DartLifecycleTest = FixtureTest; |
17 | |
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 | |
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 | |
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 | runners, // task_runners |
57 | {}, // window |
58 | {}, // snapshot_delegate |
59 | {}, // io_manager |
60 | {}, // unref_queue |
61 | {}, // image_decoder |
62 | "main.dart" , // advisory_script_uri |
63 | entrypoint.c_str(), // advisory_script_entrypoint |
64 | nullptr, // flags |
65 | settings.isolate_create_callback, // isolate create callback |
66 | settings.isolate_shutdown_callback // isolate shutdown callback |
67 | ); |
68 | |
69 | auto isolate = isolate_weak.lock(); |
70 | |
71 | if (!isolate) { |
72 | FML_LOG(ERROR) << "Could not create valid isolate." ; |
73 | return nullptr; |
74 | } |
75 | |
76 | if (DartVM::IsRunningPrecompiledCode()) { |
77 | if (!isolate->PrepareForRunningFromPrecompiledCode()) { |
78 | FML_LOG(ERROR) |
79 | << "Could not prepare to run the isolate from precompiled code." ; |
80 | return nullptr; |
81 | } |
82 | |
83 | } else { |
84 | if (!isolate->PrepareForRunningFromKernels( |
85 | settings.application_kernels())) { |
86 | FML_LOG(ERROR) << "Could not prepare isolate from application kernels." ; |
87 | return nullptr; |
88 | } |
89 | } |
90 | |
91 | if (isolate->GetPhase() != DartIsolate::Phase::Ready) { |
92 | FML_LOG(ERROR) << "Isolate was not ready." ; |
93 | return nullptr; |
94 | } |
95 | |
96 | if (!isolate->Run(entrypoint, {}, settings.root_isolate_create_callback)) { |
97 | FML_LOG(ERROR) << "Could not run entrypoint: " << entrypoint << "." ; |
98 | return nullptr; |
99 | } |
100 | |
101 | if (isolate->GetPhase() != DartIsolate::Phase::Running) { |
102 | FML_LOG(ERROR) << "Isolate was not Running." ; |
103 | return nullptr; |
104 | } |
105 | |
106 | return isolate; |
107 | } |
108 | |
109 | // TODO(chinmaygarde): This unit-test is flaky and indicates thread un-safety |
110 | // during shutdown. https://github.com/flutter/flutter/issues/36782 |
111 | TEST_F(DartLifecycleTest, DISABLED_ShuttingDownTheVMShutsDownAllIsolates) { |
112 | auto settings = CreateSettingsForFixture(); |
113 | settings.leak_vm = false; |
114 | // Make sure the service protocol launches |
115 | settings.enable_observatory = true; |
116 | |
117 | auto thread_task_runner = CreateNewThread(); |
118 | |
119 | for (size_t i = 0; i < 3; i++) { |
120 | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); |
121 | |
122 | const auto last_launch_count = DartVM::GetVMLaunchCount(); |
123 | |
124 | auto vm_ref = DartVMRef::Create(settings); |
125 | |
126 | ASSERT_TRUE(DartVMRef::IsInstanceRunning()); |
127 | ASSERT_EQ(last_launch_count + 1, DartVM::GetVMLaunchCount()); |
128 | |
129 | const size_t isolate_count = 5; |
130 | |
131 | fml::CountDownLatch latch(isolate_count); |
132 | auto vm_data = vm_ref.GetVMData(); |
133 | for (size_t i = 0; i < isolate_count; ++i) { |
134 | thread_task_runner->PostTask( |
135 | [vm_data, &settings, &latch, thread_task_runner]() { |
136 | ASSERT_TRUE(CreateAndRunRootIsolate(settings, *vm_data.get(), |
137 | thread_task_runner, |
138 | "testIsolateShutdown" )); |
139 | latch.CountDown(); |
140 | }); |
141 | } |
142 | |
143 | latch.Wait(); |
144 | } |
145 | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); |
146 | } |
147 | |
148 | } // namespace testing |
149 | } // namespace flutter |
150 | |