From e7cd520490ea0446d2c52dcebc92343abc13817f Mon Sep 17 00:00:00 2001 From: Carlo Bernaschina Date: Wed, 19 Jul 2017 15:48:32 -0700 Subject: [PATCH] Add waitUIThreadIdle service RPC (flutter/engine#3898) In https://github.com/flutter/engine/pull/3833 the `_flutter.listViews` RPC moved from thread based to lock based synchronization. The thread based synchronization side effect was used by flutter benchmarks in https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/vmservice.dart#L1223 and https://github.com/flutter/flutter/blob/master/packages/flutter_tools/lib/src/run_hot.dart#L156 to ensure the completeness of the restart/reload and so correct timing. A new RPC `_flutter.flushUIThreadTasks` is introduced to allow the flutter benchmarks to reintroduce thread based synchronization. Related https://github.com/flutter/flutter/issues/11241 --- .../common/platform_view_service_protocol.cc | 36 +++++++++++++++++-- .../common/platform_view_service_protocol.h | 18 ++++++++++ engine/src/flutter/shell/common/shell.cc | 2 +- engine/src/flutter/shell/common/shell.h | 4 +-- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/engine/src/flutter/shell/common/platform_view_service_protocol.cc b/engine/src/flutter/shell/common/platform_view_service_protocol.cc index 8e9b295e23..39385d5496 100644 --- a/engine/src/flutter/shell/common/platform_view_service_protocol.cc +++ b/engine/src/flutter/shell/common/platform_view_service_protocol.cc @@ -128,6 +128,9 @@ void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) { } Dart_RegisterRootServiceRequestCallback(kRunInViewExtensionName, &RunInView, nullptr); + // [benchmark helper] Wait for the UI Thread to idle. + Dart_RegisterRootServiceRequestCallback(kFlushUIThreadTasksExtensionName, + &FlushUIThreadTasks, nullptr); } const char* PlatformViewServiceProtocol::kRunInViewExtensionName = @@ -202,11 +205,10 @@ bool PlatformViewServiceProtocol::ListViews(const char* method, intptr_t num_params, void* user_data, const char** json_object) { - // Ask the Shell for the list of platform views. This will run a task on - // the UI thread before returning. + // Ask the Shell for the list of platform views. Shell& shell = Shell::Shared(); std::vector platform_views; - shell.WaitForPlatformViewIds(&platform_views); + shell.GetPlatformViewIds(&platform_views); std::stringstream response; @@ -314,4 +316,32 @@ void PlatformViewServiceProtocol::ScreenshotGpuTask(SkBitmap* bitmap) { canvas->flush(); } +const char* PlatformViewServiceProtocol::kFlushUIThreadTasksExtensionName = + "_flutter.flushUIThreadTasks"; + +// This API should not be invoked by production code. +// It can potentially starve the service isolate if the main isolate pauses +// at a breakpoint or is in an infinite loop. +// +// It should be invoked from the VM Service and and blocks it until UI thread +// tasks are processed. +bool PlatformViewServiceProtocol::FlushUIThreadTasks(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + ftl::AutoResetWaitableEvent latch; + blink::Threads::UI()->PostTask([&latch]() { + // This task is empty because we just need to synchronize this RPC with the + // UI Thread + latch.Signal(); + }); + + latch.Wait(); + + *json_object = strdup("{\"type\":\"Success\"}"); + return true; +} + } // namespace shell diff --git a/engine/src/flutter/shell/common/platform_view_service_protocol.h b/engine/src/flutter/shell/common/platform_view_service_protocol.h index 13a9cbae7c..d0ad2ade48 100644 --- a/engine/src/flutter/shell/common/platform_view_service_protocol.h +++ b/engine/src/flutter/shell/common/platform_view_service_protocol.h @@ -20,6 +20,8 @@ class PlatformViewServiceProtocol { private: static const char* kRunInViewExtensionName; + // It should be invoked from the VM Service and and blocks it until previous + // UI thread tasks are processed. static bool RunInView(const char* method, const char** param_keys, const char** param_values, @@ -36,6 +38,8 @@ class PlatformViewServiceProtocol { const char** json_object); static const char* kScreenshotExtensionName; + // It should be invoked from the VM Service and and blocks it until previous + // GPU thread tasks are processed. static bool Screenshot(const char* method, const char** param_keys, const char** param_values, @@ -43,6 +47,20 @@ class PlatformViewServiceProtocol { void* user_data, const char** json_object); static void ScreenshotGpuTask(SkBitmap* bitmap); + + // This API should not be invoked by production code. + // It can potentially starve the service isolate if the main isolate pauses + // at a breakpoint or is in an infinite loop. + // + // It should be invoked from the VM Service and and blocks it until previous + // GPU thread tasks are processed. + static const char* kFlushUIThreadTasksExtensionName; + static bool FlushUIThreadTasks(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); }; } // namespace shell diff --git a/engine/src/flutter/shell/common/shell.cc b/engine/src/flutter/shell/common/shell.cc index 5231480de9..5c791d45e6 100644 --- a/engine/src/flutter/shell/common/shell.cc +++ b/engine/src/flutter/shell/common/shell.cc @@ -262,7 +262,7 @@ void Shell::GetPlatformViews( *platform_views = platform_views_; } -void Shell::WaitForPlatformViewIds( +void Shell::GetPlatformViewIds( std::vector* platform_view_ids) { std::lock_guard lk(platform_views_mutex_); for (auto it = platform_views_.begin(); it != platform_views_.end(); it++) { diff --git a/engine/src/flutter/shell/common/shell.h b/engine/src/flutter/shell/common/shell.h index 6e9022239d..73ffd0e487 100644 --- a/engine/src/flutter/shell/common/shell.h +++ b/engine/src/flutter/shell/common/shell.h @@ -44,7 +44,7 @@ class Shell { // List of PlatformViews. - // These APIs must only be accessed on UI thread. + // These APIs can be called from any thread. void AddPlatformView(const std::shared_ptr& platform_view); void PurgePlatformViews(); void GetPlatformViews( @@ -58,7 +58,7 @@ class Shell { // These APIs can be called from any thread. // Return the list of platform view ids at the time of this call. - void WaitForPlatformViewIds(std::vector* platform_view_ids); + void GetPlatformViewIds(std::vector* platform_view_ids); // Attempt to run a script inside a flutter view indicated by |view_id|. // Will set |view_existed| to true if the view was found and false otherwise.