|  | // Copyright 2013 The Flutter Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "flutter/common/task_runners.h" | 
|  | #include "flutter/fml/paths.h" | 
|  | #include "flutter/fml/synchronization/count_down_latch.h" | 
|  | #include "flutter/fml/synchronization/waitable_event.h" | 
|  | #include "flutter/runtime/dart_vm.h" | 
|  | #include "flutter/runtime/dart_vm_lifecycle.h" | 
|  | #include "flutter/runtime/isolate_configuration.h" | 
|  | #include "flutter/testing/fixture_test.h" | 
|  |  | 
|  | namespace flutter { | 
|  | namespace testing { | 
|  |  | 
|  | using DartLifecycleTest = FixtureTest; | 
|  |  | 
|  | TEST_F(DartLifecycleTest, CanStartAndShutdownVM) { | 
|  | auto settings = CreateSettingsForFixture(); | 
|  | settings.leak_vm = false; | 
|  | settings.enable_vm_service = false; | 
|  | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); | 
|  | { | 
|  | auto vm_ref = DartVMRef::Create(settings); | 
|  | ASSERT_TRUE(DartVMRef::IsInstanceRunning()); | 
|  | } | 
|  | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); | 
|  | } | 
|  |  | 
|  | TEST_F(DartLifecycleTest, CanStartAndShutdownVMOverAndOver) { | 
|  | auto settings = CreateSettingsForFixture(); | 
|  | settings.leak_vm = false; | 
|  | settings.enable_vm_service = false; | 
|  | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); | 
|  | auto count = DartVM::GetVMLaunchCount(); | 
|  | for (size_t i = 0; i < 10; i++) { | 
|  | auto vm_ref = DartVMRef::Create(settings); | 
|  | ASSERT_TRUE(DartVMRef::IsInstanceRunning()); | 
|  | ASSERT_EQ(DartVM::GetVMLaunchCount(), count + 1); | 
|  | count = DartVM::GetVMLaunchCount(); | 
|  | } | 
|  | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); | 
|  | } | 
|  |  | 
|  | static std::shared_ptr<DartIsolate> CreateAndRunRootIsolate( | 
|  | const Settings& settings, | 
|  | const DartVMData& vm, | 
|  | const fml::RefPtr<fml::TaskRunner>& task_runner, | 
|  | std::string entrypoint) { | 
|  | FML_CHECK(!entrypoint.empty()); | 
|  | TaskRunners runners("io.flutter.test", task_runner, task_runner, task_runner, | 
|  | task_runner); | 
|  |  | 
|  | auto isolate_configuration = | 
|  | IsolateConfiguration::InferFromSettings(settings); | 
|  |  | 
|  | UIDartState::Context context(runners); | 
|  | context.advisory_script_uri = "main.dart"; | 
|  | context.advisory_script_entrypoint = entrypoint.c_str(); | 
|  | auto isolate = | 
|  | DartIsolate::CreateRunningRootIsolate( | 
|  | vm.GetSettings(),                    // settings | 
|  | vm.GetIsolateSnapshot(),             // isolate_snapshot | 
|  | {},                                  // platform configuration | 
|  | DartIsolate::Flags{},                // flags | 
|  | nullptr,                             // root isolate create callback | 
|  | settings.isolate_create_callback,    // isolate create callback | 
|  | settings.isolate_shutdown_callback,  // isolate shutdown callback, | 
|  | entrypoint,                          // dart entrypoint | 
|  | std::nullopt,                        // dart entrypoint library | 
|  | {},                                  // dart entrypoint arguments | 
|  | std::move(isolate_configuration),    // isolate configuration | 
|  | context                              // engine context | 
|  | ) | 
|  | .lock(); | 
|  |  | 
|  | if (!isolate) { | 
|  | FML_LOG(ERROR) << "Could not launch the root isolate."; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return isolate; | 
|  | } | 
|  |  | 
|  | // TODO(chinmaygarde): This unit-test is flaky and indicates thread un-safety | 
|  | // during shutdown. https://github.com/flutter/flutter/issues/36782 | 
|  | TEST_F(DartLifecycleTest, DISABLED_ShuttingDownTheVMShutsDownAllIsolates) { | 
|  | auto settings = CreateSettingsForFixture(); | 
|  | settings.leak_vm = false; | 
|  | // Make sure the service protocol launches | 
|  | settings.enable_vm_service = true; | 
|  |  | 
|  | auto thread_task_runner = CreateNewThread(); | 
|  |  | 
|  | for (size_t i = 0; i < 3; i++) { | 
|  | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); | 
|  |  | 
|  | const auto last_launch_count = DartVM::GetVMLaunchCount(); | 
|  |  | 
|  | auto vm_ref = DartVMRef::Create(settings); | 
|  |  | 
|  | ASSERT_TRUE(DartVMRef::IsInstanceRunning()); | 
|  | ASSERT_EQ(last_launch_count + 1, DartVM::GetVMLaunchCount()); | 
|  |  | 
|  | const size_t isolate_count = 5; | 
|  |  | 
|  | fml::CountDownLatch latch(isolate_count); | 
|  | auto vm_data = vm_ref.GetVMData(); | 
|  | for (size_t i = 0; i < isolate_count; ++i) { | 
|  | thread_task_runner->PostTask( | 
|  | [vm_data, &settings, &latch, thread_task_runner]() { | 
|  | ASSERT_TRUE(CreateAndRunRootIsolate(settings, *vm_data.get(), | 
|  | thread_task_runner, | 
|  | "testIsolateShutdown")); | 
|  | latch.CountDown(); | 
|  | }); | 
|  | } | 
|  |  | 
|  | latch.Wait(); | 
|  | } | 
|  | ASSERT_FALSE(DartVMRef::IsInstanceRunning()); | 
|  | } | 
|  |  | 
|  | }  // namespace testing | 
|  | }  // namespace flutter |