diff --git a/fml/memory/thread_checker.h b/fml/memory/thread_checker.h index 4cfd700636fc262b89878caf44aeaa22829374f4..c6314ca62128b1739d0a360950e5ea013dab839c 100644 --- a/fml/memory/thread_checker.h +++ b/fml/memory/thread_checker.h @@ -55,9 +55,7 @@ class ThreadChecker final { #endif }; -// TODO(chinmaygarde): Re-enable this after auditing all new users of -// fml::WeakPtr. -#if !defined(NDEBUG) && false +#if !defined(NDEBUG) #define FML_DECLARE_THREAD_CHECKER(c) fml::ThreadChecker c #define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) \ FML_DCHECK((c).IsCreationThreadCurrent()) diff --git a/fml/memory/weak_ptr.h b/fml/memory/weak_ptr.h index 09cc10a116b35cb52789f10228289628e1d8d84c..190865b93013fb939151227a5e7af06a0e3611ac 100644 --- a/fml/memory/weak_ptr.h +++ b/fml/memory/weak_ptr.h @@ -84,6 +84,18 @@ class WeakPtr { return *this ? ptr_ : nullptr; } + // TODO(gw280): Remove all remaining usages of getUnsafe(). + // No new usages of getUnsafe() are allowed. + // + // https://github.com/flutter/flutter/issues/42949 + T* getUnsafe() const { + // This is an unsafe method to get access to the raw pointer. + // We still check the flag_ to determine if the pointer is valid + // but callees should note that this WeakPtr could have been + // invalidated on another thread. + return flag_ && flag_->is_valid() ? ptr_ : nullptr; + } + T& operator*() const { FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); FML_DCHECK(*this); diff --git a/lib/ui/painting/image_decoder_unittests.cc b/lib/ui/painting/image_decoder_unittests.cc index 8786150d0a864002361ba1546198b333d8c8745c..b4dfece10738ab244815d1600a0acf9f8dd3edb8 100644 --- a/lib/ui/painting/image_decoder_unittests.cc +++ b/lib/ui/painting/image_decoder_unittests.cc @@ -168,11 +168,15 @@ TEST_F(ImageDecoderFixtureTest, ValidImageResultsInSuccess) { fml::AutoResetWaitableEvent latch; std::unique_ptr io_manager; - std::unique_ptr image_decoder; + auto release_io_manager = [&]() { + io_manager.reset(); + latch.Signal(); + }; auto decode_image = [&]() { - image_decoder = std::make_unique( - runners, loop->GetTaskRunner(), io_manager->GetWeakIOManager()); + std::unique_ptr image_decoder = + std::make_unique(runners, loop->GetTaskRunner(), + io_manager->GetWeakIOManager()); ImageDecoder::ImageDescriptor image_descriptor; image_descriptor.data = OpenFixtureAsSkData("DashInNooglerHat.jpg"); @@ -183,7 +187,7 @@ TEST_F(ImageDecoderFixtureTest, ValidImageResultsInSuccess) { ImageDecoder::ImageResult callback = [&](SkiaGPUObject image) { ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread()); ASSERT_TRUE(image.get()); - latch.Signal(); + runners.GetIOTaskRunner()->PostTask(release_io_manager); }; image_decoder->Decode(std::move(image_descriptor), callback); }; @@ -210,12 +214,17 @@ TEST_F(ImageDecoderFixtureTest, ExifDataIsRespectedOnDecode) { fml::AutoResetWaitableEvent latch; std::unique_ptr io_manager; - std::unique_ptr image_decoder; + + auto release_io_manager = [&]() { + io_manager.reset(); + latch.Signal(); + }; SkISize decoded_size = SkISize::MakeEmpty(); auto decode_image = [&]() { - image_decoder = std::make_unique( - runners, loop->GetTaskRunner(), io_manager->GetWeakIOManager()); + std::unique_ptr image_decoder = + std::make_unique(runners, loop->GetTaskRunner(), + io_manager->GetWeakIOManager()); ImageDecoder::ImageDescriptor image_descriptor; image_descriptor.data = OpenFixtureAsSkData("Horizontal.jpg"); @@ -227,7 +236,7 @@ TEST_F(ImageDecoderFixtureTest, ExifDataIsRespectedOnDecode) { ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread()); ASSERT_TRUE(image.get()); decoded_size = image.get()->dimensions(); - latch.Signal(); + runners.GetIOTaskRunner()->PostTask(release_io_manager); }; image_decoder->Decode(std::move(image_descriptor), callback); }; @@ -257,11 +266,16 @@ TEST_F(ImageDecoderFixtureTest, CanDecodeWithoutAGPUContext) { fml::AutoResetWaitableEvent latch; std::unique_ptr io_manager; - std::unique_ptr image_decoder; + + auto release_io_manager = [&]() { + io_manager.reset(); + latch.Signal(); + }; auto decode_image = [&]() { - image_decoder = std::make_unique( - runners, loop->GetTaskRunner(), io_manager->GetWeakIOManager()); + std::unique_ptr image_decoder = + std::make_unique(runners, loop->GetTaskRunner(), + io_manager->GetWeakIOManager()); ImageDecoder::ImageDescriptor image_descriptor; image_descriptor.data = OpenFixtureAsSkData("DashInNooglerHat.jpg"); @@ -272,7 +286,7 @@ TEST_F(ImageDecoderFixtureTest, CanDecodeWithoutAGPUContext) { ImageDecoder::ImageResult callback = [&](SkiaGPUObject image) { ASSERT_TRUE(runners.GetUITaskRunner()->RunsTasksOnCurrentThread()); ASSERT_TRUE(image.get()); - latch.Signal(); + runners.GetIOTaskRunner()->PostTask(release_io_manager); }; image_decoder->Decode(std::move(image_descriptor), callback); }; @@ -355,6 +369,20 @@ TEST_F(ImageDecoderFixtureTest, CanDecodeWithResizes) { ASSERT_EQ(decoded_size(100, {}), SkISize::Make(100, 133)); ASSERT_EQ(decoded_size({}, 100), SkISize::Make(75, 100)); ASSERT_EQ(decoded_size(100, 100), SkISize::Make(100, 100)); + + // Destroy the IO manager + runners.GetIOTaskRunner()->PostTask([&]() { + io_manager.reset(); + latch.Signal(); + }); + latch.Wait(); + + // Destroy the image decoder + runners.GetUITaskRunner()->PostTask([&]() { + image_decoder.reset(); + latch.Signal(); + }); + latch.Wait(); } TEST_F(ImageDecoderFixtureTest, CanResizeWithoutDecode) { @@ -441,6 +469,20 @@ TEST_F(ImageDecoderFixtureTest, CanResizeWithoutDecode) { ASSERT_EQ(decoded_size(100, {}), SkISize::Make(100, 133)); ASSERT_EQ(decoded_size({}, 100), SkISize::Make(75, 100)); ASSERT_EQ(decoded_size(100, 100), SkISize::Make(100, 100)); + + // Destroy the IO manager + runners.GetIOTaskRunner()->PostTask([&]() { + io_manager.reset(); + latch.Signal(); + }); + latch.Wait(); + + // Destroy the image decoder + runners.GetUITaskRunner()->PostTask([&]() { + image_decoder.reset(); + latch.Signal(); + }); + latch.Wait(); } } // namespace testing diff --git a/lib/ui/ui_dart_state.cc b/lib/ui/ui_dart_state.cc index 41b12b6b21a4768238aa6038c47682bee126248c..4eb022d8c23bc65e847381df0df5cc318f73350d 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -79,10 +79,16 @@ const TaskRunners& UIDartState::GetTaskRunners() const { } fml::RefPtr UIDartState::GetSkiaUnrefQueue() const { - if (!io_manager_) { + // TODO(gw280): The WeakPtr here asserts that we are derefing it on the + // same thread as it was created on. As we can't guarantee that currently + // we're being called from the IO thread (construction thread), we need + // to use getUnsafe() here to avoid failing the assertion. + // + // https://github.com/flutter/flutter/issues/42946 + if (!io_manager_.getUnsafe()) { return nullptr; } - return io_manager_->GetSkiaUnrefQueue(); + return io_manager_.getUnsafe()->GetSkiaUnrefQueue(); } void UIDartState::ScheduleMicrotask(Dart_Handle closure) { @@ -114,6 +120,7 @@ void UIDartState::AddOrRemoveTaskObserver(bool add) { } fml::WeakPtr UIDartState::GetResourceContext() const { + FML_DCHECK(task_runners_.GetIOTaskRunner()->RunsTasksOnCurrentThread()); if (!io_manager_) { return {}; } diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index 1654e75c9bea65231110c7746bb2b1afa31d6474..321cba391e86f8b242007365cabfdf69f93fd981 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -14,6 +14,7 @@ #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/build_config.h" #include "flutter/fml/memory/weak_ptr.h" +#include "flutter/fml/synchronization/waitable_event.h" #include "flutter/lib/ui/io_manager.h" #include "flutter/lib/ui/isolate_name_server/isolate_name_server.h" #include "flutter/lib/ui/painting/image_decoder.h" diff --git a/shell/common/input_events_unittests.cc b/shell/common/input_events_unittests.cc index 69688cce4a589a9560b400aa859b7efbbdb783a5..187bde7a35f1ccd0484ee0685b1c7586277775f8 100644 --- a/shell/common/input_events_unittests.cc +++ b/shell/common/input_events_unittests.cc @@ -127,7 +127,14 @@ static void TestSimulatedInputEvents( }); simulation.wait(); - shell.reset(); + + TaskRunners task_runners = fixture->GetTaskRunnersForFixture(); + fml::AutoResetWaitableEvent latch; + task_runners.GetPlatformTaskRunner()->PostTask([&shell, &latch]() mutable { + shell.reset(); + latch.Signal(); + }); + latch.Wait(); // Make sure that all events have been consumed so // https://github.com/flutter/flutter/issues/40863 won't happen again. diff --git a/shell/common/persistent_cache_unittests.cc b/shell/common/persistent_cache_unittests.cc index f097596e6fc4534c58fb8d3c3c92ea3f0fa0664c..62b36e786875b496291d6016f174fada47874ccb 100644 --- a/shell/common/persistent_cache_unittests.cc +++ b/shell/common/persistent_cache_unittests.cc @@ -87,7 +87,7 @@ TEST_F(ShellTest, CacheSkSLWorks) { settings.dump_skp_on_shader_compilation = true; auto normal_config = RunConfiguration::InferFromSettings(settings); normal_config.SetEntrypoint("emptyMain"); - shell.reset(); + DestroyShell(std::move(shell)); shell = CreateShell(settings); PlatformViewNotifyCreated(shell.get()); RunEngine(shell.get(), std::move(normal_config)); @@ -120,6 +120,7 @@ TEST_F(ShellTest, CacheSkSLWorks) { return true; }; fml::VisitFiles(dir.fd(), remove_visitor); + DestroyShell(std::move(shell)); } } // namespace testing diff --git a/shell/common/shell.cc b/shell/common/shell.cc index d31b0dcc3a8b62f6996b63172730d5e61eda116a..bf185a6b366174207e816fb484eceaf82d93fe2c 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -90,6 +90,13 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( std::promise> weak_io_manager_promise; auto weak_io_manager_future = weak_io_manager_promise.get_future(); auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner(); + + // TODO(gw280): The WeakPtr here asserts that we are derefing it on the + // same thread as it was created on. We are currently on the IO thread + // inside this lambda but we need to deref the PlatformView, which was + // constructed on the platform thread. + // + // https://github.com/flutter/flutter/issues/42948 fml::TaskRunner::RunNowOrPostTask( io_task_runner, [&io_manager_promise, // @@ -99,7 +106,7 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( ]() { TRACE_EVENT0("flutter", "ShellSetupIOSubsystem"); auto io_manager = std::make_unique( - platform_view->CreateResourceContext(), io_task_runner); + platform_view.getUnsafe()->CreateResourceContext(), io_task_runner); weak_io_manager_promise.set_value(io_manager->GetWeakPtr()); io_manager_promise.set_value(std::move(io_manager)); }); @@ -277,11 +284,21 @@ Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings) : task_runners_(std::move(task_runners)), settings_(std::move(settings)), vm_(std::move(vm)), - weak_factory_(this) { + weak_factory_(this), + weak_factory_gpu_(nullptr) { FML_CHECK(vm_) << "Must have access to VM to create a shell."; FML_DCHECK(task_runners_.IsValid()); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + // Generate a WeakPtrFactory for use with the GPU thread. This does not need + // to wait on a latch because it can only ever be used from the GPU thread + // from this class, so we have ordering guarantees. + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetGPUTaskRunner(), fml::MakeCopyable([this]() mutable { + this->weak_factory_gpu_ = + std::make_unique>(this); + })); + // Install service protocol handlers. service_protocol_handlers_[ServiceProtocol::kScreenshotExtensionName] = { @@ -331,11 +348,13 @@ Shell::~Shell() { fml::TaskRunner::RunNowOrPostTask( task_runners_.GetGPUTaskRunner(), - fml::MakeCopyable( - [rasterizer = std::move(rasterizer_), &gpu_latch]() mutable { - rasterizer.reset(); - gpu_latch.Signal(); - })); + fml::MakeCopyable([rasterizer = std::move(rasterizer_), + weak_factory_gpu = std::move(weak_factory_gpu_), + &gpu_latch]() mutable { + rasterizer.reset(); + weak_factory_gpu.reset(); + gpu_latch.Signal(); + })); gpu_latch.Wait(); fml::TaskRunner::RunNowOrPostTask( @@ -393,9 +412,6 @@ void Shell::RunEngine(RunConfiguration run_configuration, FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - if (!weak_engine_) { - result(Engine::RunStatus::Failure); - } fml::TaskRunner::RunNowOrPostTask( task_runners_.GetUITaskRunner(), fml::MakeCopyable( @@ -486,8 +502,13 @@ bool Shell::Setup(std::unique_ptr platform_view, PersistentCache::GetCacheForProcess()->SetIsDumpingSkp( settings_.dump_skp_on_shader_compilation); - // Shell::Setup is running on the UI thread so we can do the following. - display_refresh_rate_ = weak_engine_->GetDisplayRefreshRate(); + // TODO(gw280): The WeakPtr here asserts that we are derefing it on the + // same thread as it was created on. Shell is constructed on the platform + // thread but we need to call into the Engine on the UI thread, so we need + // to use getUnsafe() here to avoid failing the assertion. + // + // https://github.com/flutter/flutter/issues/42947 + display_refresh_rate_ = weak_engine_.getUnsafe()->GetDisplayRefreshRate(); return true; } @@ -1069,7 +1090,7 @@ void Shell::OnFrameRasterized(const FrameTiming& timing) { // never be reported until the next animation starts. frame_timings_report_scheduled_ = true; task_runners_.GetGPUTaskRunner()->PostDelayedTask( - [self = weak_factory_.GetWeakPtr()]() { + [self = weak_factory_gpu_->GetWeakPtr()]() { if (!self.get()) { return; } diff --git a/shell/common/shell.h b/shell/common/shell.h index c6753912771d3a5280394ed7d15159c3b397acda..e4ee6960389ad06a5f6f170582e5487a53bed502 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -74,7 +74,8 @@ enum class DartErrorCode { /// platform task runner. In case the embedder wants to directly access a shell /// subcomponent, it is the embedder's responsibility to acquire a weak pointer /// to that component and post a task to the task runner used by the component -/// to access its methods. +/// to access its methods. The shell must also be destroyed on the platform +/// task runner. /// /// There is no explicit API to bootstrap and shutdown the Dart VM. The first /// instance of the shell in the process bootstraps the Dart VM and the @@ -516,6 +517,10 @@ class Shell final : public PlatformView::Delegate, fml::WeakPtrFactory weak_factory_; + // For accessing the Shell via the GPU thread, necessary for various + // rasterizer callbacks. + std::unique_ptr> weak_factory_gpu_; + friend class testing::ShellTest; FML_DISALLOW_COPY_AND_ASSIGN(Shell); diff --git a/shell/common/shell_benchmarks.cc b/shell/common/shell_benchmarks.cc index f161d56e92b8ca2ecf362ada327d35358553d01d..f7eb44e4c551ac18ce1d6c57e283307fe8a731be 100644 --- a/shell/common/shell_benchmarks.cc +++ b/shell/common/shell_benchmarks.cc @@ -78,7 +78,15 @@ static void StartupAndShutdownShell(benchmark::State& state, { benchmarking::ScopedPauseTiming pause(state, !measure_shutdown); - shell.reset(); // Shutdown is synchronous. + // Shutdown must occur synchronously on the platform thread. + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask( + thread_host->platform_thread->GetTaskRunner(), + [&shell, &latch]() mutable { + shell.reset(); + latch.Signal(); + }); + latch.Wait(); thread_host.reset(); } diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index fa937a86c5626457e10f69d7f5c5a4f1cf0b15cb..51370d082862b6a4097b350c15c4af0b1b9a3954 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -245,6 +245,21 @@ std::unique_ptr ShellTest::CreateShell(Settings settings, }); } +void ShellTest::DestroyShell(std::unique_ptr shell) { + DestroyShell(std::move(shell), GetTaskRunnersForFixture()); +} + +void ShellTest::DestroyShell(std::unique_ptr shell, + TaskRunners task_runners) { + fml::AutoResetWaitableEvent latch; + fml::TaskRunner::RunNowOrPostTask(task_runners.GetPlatformTaskRunner(), + [&shell, &latch]() mutable { + shell.reset(); + latch.Signal(); + }); + latch.Wait(); +} + // |testing::ThreadTest| void ShellTest::SetUp() { ThreadTest::SetUp(); diff --git a/shell/common/shell_test.h b/shell/common/shell_test.h index e1671263630bc62ff0272ea5743f924668629444..fdee9653b71ce59a5e84502b47ce8b5d6d535bc4 100644 --- a/shell/common/shell_test.h +++ b/shell/common/shell_test.h @@ -34,6 +34,8 @@ class ShellTest : public ThreadTest { std::unique_ptr CreateShell(Settings settings, TaskRunners task_runners, bool simulate_vsync = false); + void DestroyShell(std::unique_ptr shell); + void DestroyShell(std::unique_ptr shell, TaskRunners task_runners); TaskRunners GetTaskRunnersForFixture(); void SendEnginePlatformMessage(Shell* shell, diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index bf9cbc4aea2fdc32b0fc8c2e8df2d653e629f51f..942db37c943c67eb6231e56e03d2949b1df0d43f 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -75,7 +75,7 @@ TEST_F(ShellTest, InitializeWithDifferentThreads) { auto shell = CreateShell(std::move(settings), std::move(task_runners)); ASSERT_TRUE(ValidateShell(shell.get())); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); - shell.reset(); + DestroyShell(std::move(shell), std::move(task_runners)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -87,10 +87,10 @@ TEST_F(ShellTest, InitializeWithSingleThread) { auto task_runner = thread_host.platform_thread->GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(std::move(settings), std::move(task_runners)); + auto shell = CreateShell(std::move(settings), task_runners); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); - shell.reset(); + DestroyShell(std::move(shell), std::move(task_runners)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -101,10 +101,10 @@ TEST_F(ShellTest, InitializeWithSingleThreadWhichIsTheCallingThread) { auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); - auto shell = CreateShell(std::move(settings), std::move(task_runners)); + auto shell = CreateShell(std::move(settings), task_runners); ASSERT_TRUE(ValidateShell(shell.get())); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); - shell.reset(); + DestroyShell(std::move(shell), std::move(task_runners)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -132,7 +132,7 @@ TEST_F(ShellTest, }); ASSERT_TRUE(ValidateShell(shell.get())); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); - shell.reset(); + DestroyShell(std::move(shell), std::move(task_runners)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -152,7 +152,7 @@ TEST_F(ShellTest, InitializeWithGPUAndPlatformThreadsTheSame) { auto shell = CreateShell(std::move(settings), std::move(task_runners)); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); ASSERT_TRUE(ValidateShell(shell.get())); - shell.reset(); + DestroyShell(std::move(shell), std::move(task_runners)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -174,7 +174,7 @@ TEST_F(ShellTest, FixturesAreFunctional) { RunEngine(shell.get(), std::move(configuration)); main_latch.Wait(); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); - shell.reset(); + DestroyShell(std::move(shell)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -198,7 +198,7 @@ TEST_F(ShellTest, SecondaryIsolateBindingsAreSetupViaShellSettings) { latch.Wait(); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); - shell.reset(); + DestroyShell(std::move(shell)); ASSERT_FALSE(DartVMRef::IsInstanceRunning()); } @@ -281,6 +281,7 @@ TEST_F(ShellTest, NoNeedToReportTimingsByDefault) { // positive in any tests. Otherwise those tests will be flaky as the clearing // of unreported timings is unpredictive. ASSERT_EQ(UnreportedTimingsCount(shell.get()), 0); + DestroyShell(std::move(shell)); } TEST_F(ShellTest, NeedsReportTimingsIsSetWithCallback) { @@ -296,6 +297,7 @@ TEST_F(ShellTest, NeedsReportTimingsIsSetWithCallback) { RunEngine(shell.get(), std::move(configuration)); PumpOneFrame(shell.get()); ASSERT_TRUE(GetNeedsReportTimings(shell.get())); + DestroyShell(std::move(shell)); } static void CheckFrameTimings(const std::vector& timings, @@ -350,7 +352,7 @@ TEST_F(ShellTest, ReportTimingsIsCalled) { } reportLatch.Wait(); - shell.reset(); + DestroyShell(std::move(shell)); fml::TimePoint finish = fml::TimePoint::Now(); ASSERT_TRUE(timestamps.size() > 0); @@ -420,6 +422,7 @@ TEST_F(ShellTest, FrameRasterizedCallbackIsCalled) { int64_t build_start = timing.Get(FrameTiming::kBuildStart).ToEpochDelta().ToMicroseconds(); ASSERT_EQ(build_start, begin_frame); + DestroyShell(std::move(shell)); } TEST(SettingsTest, FrameTimingSetsAndGetsProperly) { @@ -474,7 +477,7 @@ TEST_F(ShellTest, ReportTimingsIsCalledSoonerInNonReleaseMode) { PumpOneFrame(shell.get()); reportLatch.Wait(); - shell.reset(); + DestroyShell(std::move(shell)); fml::TimePoint finish = fml::TimePoint::Now(); fml::TimeDelta ellapsed = finish - start; @@ -518,7 +521,7 @@ TEST_F(ShellTest, ReportTimingsIsCalledImmediatelyAfterTheFirstFrame) { } reportLatch.Wait(); - shell.reset(); + DestroyShell(std::move(shell)); // Check for the immediate callback of the first frame that doesn't wait for // the other 9 frames to be rasterized. @@ -570,6 +573,7 @@ TEST_F(ShellTest, WaitForFirstFrame) { fml::Status result = shell->WaitForFirstFrame(fml::TimeDelta::FromMilliseconds(1000)); ASSERT_TRUE(result.ok()); + DestroyShell(std::move(shell)); } TEST_F(ShellTest, WaitForFirstFrameTimeout) { @@ -586,6 +590,7 @@ TEST_F(ShellTest, WaitForFirstFrameTimeout) { fml::Status result = shell->WaitForFirstFrame(fml::TimeDelta::FromMilliseconds(10)); ASSERT_EQ(result.code(), fml::StatusCode::kDeadlineExceeded); + DestroyShell(std::move(shell)); } TEST_F(ShellTest, WaitForFirstFrameMultiple) { @@ -607,6 +612,7 @@ TEST_F(ShellTest, WaitForFirstFrameMultiple) { result = shell->WaitForFirstFrame(fml::TimeDelta::FromMilliseconds(1)); ASSERT_TRUE(result.ok()); } + DestroyShell(std::move(shell)); } /// Makes sure that WaitForFirstFrame works if we rendered a frame with the @@ -635,6 +641,7 @@ TEST_F(ShellTest, WaitForFirstFrameInlined) { event.Signal(); }); ASSERT_FALSE(event.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(1000))); + DestroyShell(std::move(shell), std::move(task_runners)); } static size_t GetRasterizerResourceCacheBytesSync(Shell& shell) { @@ -699,6 +706,7 @@ TEST_F(ShellTest, SetResourceCacheSize) { PumpOneFrame(shell.get()); EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), 10000U); + DestroyShell(std::move(shell), std::move(task_runners)); } TEST_F(ShellTest, SetResourceCacheSizeEarly) { @@ -727,6 +735,7 @@ TEST_F(ShellTest, SetResourceCacheSizeEarly) { EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), static_cast(3840000U)); + DestroyShell(std::move(shell), std::move(task_runners)); } TEST_F(ShellTest, SetResourceCacheSizeNotifiesDart) { @@ -765,6 +774,7 @@ TEST_F(ShellTest, SetResourceCacheSizeNotifiesDart) { EXPECT_EQ(GetRasterizerResourceCacheBytesSync(*shell), static_cast(10000U)); + DestroyShell(std::move(shell), std::move(task_runners)); } TEST_F(ShellTest, CanCreateImagefromDecompressedBytes) { @@ -798,6 +808,7 @@ TEST_F(ShellTest, CanCreateImagefromDecompressedBytes) { RunEngine(shell.get(), std::move(configuration)); latch.Wait(); + DestroyShell(std::move(shell), std::move(task_runners)); } class MockTexture : public Texture { @@ -872,6 +883,7 @@ TEST_F(ShellTest, TextureFrameMarkedAvailableAndUnregister) { latch->Wait(); EXPECT_EQ(mockTexture->unregistered(), true); + DestroyShell(std::move(shell), std::move(task_runners)); } TEST_F(ShellTest, IsolateCanAccessPersistentIsolateData) { @@ -910,6 +922,7 @@ TEST_F(ShellTest, IsolateCanAccessPersistentIsolateData) { }); message_latch.Wait(); + DestroyShell(std::move(shell), std::move(task_runners)); } } // namespace testing