From 3ed2fb026e0b42da7d4b749bbaf84f1fe891713b Mon Sep 17 00:00:00 2001 From: John McCutchan Date: Wed, 3 Aug 2016 15:55:31 -0700 Subject: [PATCH] Add collection of PlatformViews to the Shell and allow them to be queried over the service protocol (#2861) --- sky/engine/core/script/dart_init.cc | 13 ++++ sky/engine/core/script/dart_init.h | 6 ++ sky/shell/BUILD.gn | 2 + sky/shell/platform_view.cc | 10 +++ sky/shell/platform_view_service_protocol.cc | 79 +++++++++++++++++++++ sky/shell/platform_view_service_protocol.h | 41 +++++++++++ sky/shell/shell.cc | 59 +++++++++++++++ sky/shell/shell.h | 21 ++++++ 8 files changed, 231 insertions(+) create mode 100644 sky/shell/platform_view_service_protocol.cc create mode 100644 sky/shell/platform_view_service_protocol.h diff --git a/sky/engine/core/script/dart_init.cc b/sky/engine/core/script/dart_init.cc index 15f964a09..a18095053 100644 --- a/sky/engine/core/script/dart_init.cc +++ b/sky/engine/core/script/dart_init.cc @@ -129,6 +129,8 @@ const char kDartFlags[] = "dart-flags"; bool g_service_isolate_initialized = false; ServiceIsolateHook g_service_isolate_hook = nullptr; +RegisterNativeServiceProtocolExtensionHook + g_register_native_service_protocol_extensions_hook = nullptr; void IsolateShutdownCallback(void* callback_data) { DartState* dart_state = static_cast(callback_data); @@ -211,6 +213,11 @@ Dart_Isolate ServiceIsolateCreateCallback(const char* script_uri, Dart_ExitIsolate(); g_service_isolate_initialized = true; + // Register any native service protocol extensions. + if (g_register_native_service_protocol_extensions_hook) { + g_register_native_service_protocol_extensions_hook( + IsRunningPrecompiledCode()); + } return isolate; } @@ -496,6 +503,12 @@ void SetServiceIsolateHook(ServiceIsolateHook hook) { g_service_isolate_hook = hook; } +void SetRegisterNativeServiceProtocolExtensionHook( + RegisterNativeServiceProtocolExtensionHook hook) { + CHECK(!g_service_isolate_initialized); + g_register_native_service_protocol_extensions_hook = hook; +} + static bool ShouldEnableCheckedMode() { if (IsRunningPrecompiledCode()) { // Checked mode is never enabled during precompilation. Even snapshot diff --git a/sky/engine/core/script/dart_init.h b/sky/engine/core/script/dart_init.h index 941ea74f4..175dcba3f 100644 --- a/sky/engine/core/script/dart_init.h +++ b/sky/engine/core/script/dart_init.h @@ -42,6 +42,7 @@ bool IsRunningPrecompiledCode(); using EmbedderTracingCallback = base::Callback; typedef void (*ServiceIsolateHook)(bool); +typedef void (*RegisterNativeServiceProtocolExtensionHook)(bool); struct EmbedderTracingCallbacks { EmbedderTracingCallback start_tracing_callback; @@ -60,6 +61,11 @@ void SetEmbedderTracingCallbacks( // service isolate. void SetServiceIsolateHook(ServiceIsolateHook hook); +// Provide a function that will be called to register native service protocol +// extensions. +void SetRegisterNativeServiceProtocolExtensionHook( + RegisterNativeServiceProtocolExtensionHook hook); + Dart_Handle DartLibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url); diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn index a66a0da15..7b4b05bc4 100644 --- a/sky/shell/BUILD.gn +++ b/sky/shell/BUILD.gn @@ -23,6 +23,8 @@ source_set("common") { "gpu/picture_serializer.h", "platform_view.cc", "platform_view.h", + "platform_view_service_protocol.cc", + "platform_view_service_protocol.h", "rasterizer.cc", "rasterizer.h", "shell.cc", diff --git a/sky/shell/platform_view.cc b/sky/shell/platform_view.cc index 8be7af9e7..0acf915ad 100644 --- a/sky/shell/platform_view.cc +++ b/sky/shell/platform_view.cc @@ -50,6 +50,10 @@ PlatformView::PlatformView() PlatformView::~PlatformView() { Shell& shell = Shell::Shared(); + // Purge dead PlatformViews. + shell.ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&Shell::PurgePlatformViews, base::Unretained(&shell))); shell.gpu_task_runner()->DeleteSoon(FROM_HERE, rasterizer_.release()); shell.ui_task_runner()->DeleteSoon(FROM_HERE, engine_.release()); } @@ -58,6 +62,12 @@ void PlatformView::ConnectToEngine(mojo::InterfaceRequest request) { config_.ui_task_runner->PostTask( FROM_HERE, base::Bind(&UIDelegate::ConnectToEngine, config_.ui_delegate, base::Passed(&request))); + Shell& shell = Shell::Shared(); + shell.ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&Shell::AddPlatformView, + base::Unretained(&shell), + GetWeakViewPtr())); } void PlatformView::NotifyCreated() { diff --git a/sky/shell/platform_view_service_protocol.cc b/sky/shell/platform_view_service_protocol.cc new file mode 100644 index 000000000..917bfdf4f --- /dev/null +++ b/sky/shell/platform_view_service_protocol.cc @@ -0,0 +1,79 @@ +// Copyright 2016 The Chromium 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 "sky/shell/platform_view_service_protocol.h" + +#include "sky/shell/shell.h" + +namespace sky { +namespace shell { + +void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) { + if (running_precompiled_code) { + return; + } + Dart_RegisterRootServiceRequestCallback(kRunInViewExtensionName, + &RunInView, + nullptr); + Dart_RegisterRootServiceRequestCallback(kListViewsExtensionName, + &ListViews, + nullptr); +} + +const char* PlatformViewServiceProtocol::kRunInViewExtensionName = + "_flutter.runInView"; + +bool PlatformViewServiceProtocol::RunInView(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + // TODO(johnmccutchan): Implement this. + *json_object = strdup("{\"type\": \"Success\"}"); + return true; +} + +const char* PlatformViewServiceProtocol::kListViewsExtensionName = + "_flutter.listViews"; + +bool PlatformViewServiceProtocol::ListViews(const char* method, + const char** param_keys, + const char** param_values, + 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. + Shell& shell = Shell::Shared(); + std::vector> platform_views; + shell.WaitForPlatformViews(&platform_views); + + std::stringstream response; + + response << "{\"type\":\"FlutterViewList\",\"views\":["; + bool prefix_comma = false; + for (auto it = platform_views.begin(); it != platform_views.end(); it++) { + PlatformView* view = it->get(); + if (!view) { + // Skip any platform views which have been deleted. + continue; + } + if (prefix_comma) { + response << ','; + } else { + prefix_comma = true; + } + response << "{\"type\":\"FlutterView\", \"id\": \"_flutterView/"; + response << "0x" << std::hex << reinterpret_cast(view); + response << "\"}"; + } + response << "]}"; + // Copy the response. + *json_object = strdup(response.str().c_str()); + return true; +} + +} // namespace shell +} // namespace sky diff --git a/sky/shell/platform_view_service_protocol.h b/sky/shell/platform_view_service_protocol.h new file mode 100644 index 000000000..475c5a4e8 --- /dev/null +++ b/sky/shell/platform_view_service_protocol.h @@ -0,0 +1,41 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKY_SHELL_PLATFORM_VIEW_SERVICE_PROTOCOL_H_ +#define SKY_SHELL_PLATFORM_VIEW_SERVICE_PROTOCOL_H_ + +#include + +#include "sky/shell/platform_view.h" +#include "dart/runtime/include/dart_tools_api.h" + +namespace sky { +namespace shell { + +class PlatformViewServiceProtocol { + public: + static void RegisterHook(bool running_precompiled_code); + + private: + static const char* kRunInViewExtensionName; + static bool RunInView(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + + static const char* kListViewsExtensionName; + static bool ListViews(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); +}; + +} // namespace shell +} // namespace sky + +#endif // SKY_SHELL_PLATFORM_VIEW_SERVICE_PROTOCOL_H_ diff --git a/sky/shell/shell.cc b/sky/shell/shell.cc index 7142be2cb..93d07d230 100644 --- a/sky/shell/shell.cc +++ b/sky/shell/shell.cc @@ -17,11 +17,13 @@ #include "base/posix/eintr_wrapper.h" #include "base/single_thread_task_runner.h" #include "base/trace_event/trace_event.h" +#include "dart/runtime/include/dart_tools_api.h" #include "mojo/message_pump/message_pump_mojo.h" #include "skia/ext/event_tracer_impl.h" #include "sky/engine/core/script/dart_init.h" #include "sky/engine/public/platform/sky_settings.h" #include "sky/shell/diagnostic/diagnostic_server.h" +#include "sky/shell/platform_view_service_protocol.h" #include "sky/shell/switches.h" #include "sky/shell/ui/engine.h" @@ -39,6 +41,10 @@ bool IsInvalid(const base::WeakPtr& rasterizer) { return !rasterizer; } +bool IsViewInvalid(const base::WeakPtr& platform_view) { + return !platform_view; +} + class NonDiscardableMemory : public base::DiscardableMemory { public: explicit NonDiscardableMemory(size_t size) : data_(new uint8_t[size]) {} @@ -85,12 +91,16 @@ Shell::Shell() { ui_thread_.reset(new base::Thread("ui_thread")); ui_thread_->StartWithOptions(options); ui_task_runner_ = ui_thread_->message_loop()->task_runner(); + ui_task_runner_->PostTask( + FROM_HERE, base::Bind(&Shell::InitUIThread, base::Unretained(this))); io_thread_.reset(new base::Thread("io_thread")); io_thread_->StartWithOptions(options); io_task_runner_ = io_thread_->message_loop()->task_runner(); blink::SetServiceIsolateHook(ServiceIsolateHook); + blink::SetRegisterNativeServiceProtocolExtensionHook( + PlatformViewServiceProtocol::RegisterHook); } Shell::~Shell() {} @@ -172,6 +182,12 @@ void Shell::InitGpuThread() { gpu_thread_checker_.reset(new base::ThreadChecker()); } + +void Shell::InitUIThread() { + ui_thread_checker_.reset(new base::ThreadChecker()); +} + + void Shell::AddRasterizer(const base::WeakPtr& rasterizer) { DCHECK(gpu_thread_checker_ && gpu_thread_checker_->CalledOnValidThread()); rasterizers_.push_back(rasterizer); @@ -190,5 +206,48 @@ void Shell::GetRasterizers( *rasterizers = rasterizers_; } +void Shell::AddPlatformView(const base::WeakPtr& platform_view) { + DCHECK(ui_thread_checker_ && ui_thread_checker_->CalledOnValidThread()); + if (platform_view) { + platform_views_.push_back(platform_view); + } +} + +void Shell::PurgePlatformViews() { + DCHECK(ui_thread_checker_ && ui_thread_checker_->CalledOnValidThread()); + platform_views_.erase(std::remove_if(platform_views_.begin(), + platform_views_.end(), + IsViewInvalid), + platform_views_.end()); +} + +void Shell::GetPlatformViews( + std::vector>* platform_views) { + DCHECK(ui_thread_checker_ && ui_thread_checker_->CalledOnValidThread()); + *platform_views = platform_views_; +} + +void Shell::WaitForPlatformViews( + std::vector>* platform_views) { + + base::WaitableEvent latch(false, false); + + ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&Shell::WaitForPlatformViewsUIThread, + base::Unretained(this), + base::Unretained(platform_views), + base::Unretained(&latch))); + + latch.Wait(); +} + +void Shell::WaitForPlatformViewsUIThread( + std::vector>* platform_views, + base::WaitableEvent* latch) { + GetPlatformViews(platform_views); + latch->Signal(); +} + } // namespace shell } // namespace sky diff --git a/sky/shell/shell.h b/sky/shell/shell.h index 692a70a86..f5c2962fe 100644 --- a/sky/shell/shell.h +++ b/sky/shell/shell.h @@ -9,12 +9,14 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" +#include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "sky/shell/tracing_controller.h" namespace sky { namespace shell { +class PlatformView; class Rasterizer; class Shell { @@ -49,10 +51,27 @@ class Shell { void PurgeRasterizers(); void GetRasterizers(std::vector>* rasterizer); + // List of PlatformViews. + + // These APIs must only be accessed on UI thread. + void AddPlatformView(const base::WeakPtr& platform_view); + void PurgePlatformViews(); + void GetPlatformViews(std::vector>* + platform_views); + + // These APIs can be called from any thread. + void WaitForPlatformViews( + std::vector>* platform_views); + private: Shell(); void InitGpuThread(); + void InitUIThread(); + + void WaitForPlatformViewsUIThread( + std::vector>* platform_views, + base::WaitableEvent* latch); std::unique_ptr gpu_thread_; std::unique_ptr ui_thread_; @@ -63,10 +82,12 @@ class Shell { scoped_refptr io_task_runner_; std::unique_ptr gpu_thread_checker_; + std::unique_ptr ui_thread_checker_; TracingController tracing_controller_; std::vector> rasterizers_; + std::vector> platform_views_; DISALLOW_COPY_AND_ASSIGN(Shell); }; -- GitLab