| // 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/testing/fixture_test.h" | |
| namespace flutter { | |
| namespace testing { | |
| using DartLifecycleTest = FixtureTest; | |
| TEST_F(DartLifecycleTest, CanStartAndShutdownVM) { | |
| auto settings = CreateSettingsForFixture(); | |
| settings.leak_vm = false; | |
| settings.enable_observatory = 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_observatory = 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, | |
| fml::RefPtr<fml::TaskRunner> task_runner, | |
| std::string entrypoint) { | |
| FML_CHECK(entrypoint.size() > 0); | |
| TaskRunners runners("io.flutter.test", task_runner, task_runner, task_runner, | |
| task_runner); | |
| auto isolate_weak = DartIsolate::CreateRootIsolate( | |
| vm.GetSettings(), // settings | |
| vm.GetIsolateSnapshot(), // isolate_snapshot | |
| runners, // task_runners | |
| {}, // window | |
| {}, // snapshot_delegate | |
| {}, // hint_freed_delegate | |
| {}, // io_manager | |
| {}, // unref_queue | |
| {}, // image_decoder | |
| "main.dart", // advisory_script_uri | |
| entrypoint.c_str(), // advisory_script_entrypoint | |
| nullptr, // flags | |
| settings.isolate_create_callback, // isolate create callback | |
| settings.isolate_shutdown_callback // isolate shutdown callback | |
| ); | |
| auto isolate = isolate_weak.lock(); | |
| if (!isolate) { | |
| FML_LOG(ERROR) << "Could not create valid isolate."; | |
| return nullptr; | |
| } | |
| if (DartVM::IsRunningPrecompiledCode()) { | |
| if (!isolate->PrepareForRunningFromPrecompiledCode()) { | |
| FML_LOG(ERROR) | |
| << "Could not prepare to run the isolate from precompiled code."; | |
| return nullptr; | |
| } | |
| } else { | |
| if (!isolate->PrepareForRunningFromKernels( | |
| settings.application_kernels())) { | |
| FML_LOG(ERROR) << "Could not prepare isolate from application kernels."; | |
| return nullptr; | |
| } | |
| } | |
| if (isolate->GetPhase() != DartIsolate::Phase::Ready) { | |
| FML_LOG(ERROR) << "Isolate was not ready."; | |
| return nullptr; | |
| } | |
| if (!isolate->Run(entrypoint, {}, settings.root_isolate_create_callback)) { | |
| FML_LOG(ERROR) << "Could not run entrypoint: " << entrypoint << "."; | |
| return nullptr; | |
| } | |
| if (isolate->GetPhase() != DartIsolate::Phase::Running) { | |
| FML_LOG(ERROR) << "Isolate was not Running."; | |
| 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_observatory = 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 |