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
13namespace flutter {
14namespace testing {
15
16using DartLifecycleTest = FixtureTest;
17
18TEST_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
30TEST_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
45static 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
111TEST_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