Commit 6fa1de44 authored by Shawn Gallea's avatar Shawn Gallea Committed by Commit Bot

Add PlatformViewsRpcInstance

This allows custom implementations that can share base functionality.
This is needed since instances must be created to control both web views
and cast apps.

Bug: b/136460199
Test: Compile cast_shell
Change-Id: Id19507b3127f4bd2071e02f4b2cd4ec931c7ea71
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1872466Reviewed-by: default avatarDaniel Nicoara <dnicoara@chromium.org>
Commit-Queue: Shawn Gallea <sagallea@google.com>
Cr-Commit-Position: refs/heads/master@{#707915}
parent bb9e9ac8
......@@ -382,6 +382,8 @@ cast_source_set("browser") {
"exo/cast_wm_helper.h",
"exo/wayland_server_controller.cc",
"exo/wayland_server_controller.h",
"webview/platform_views_rpc_instance.cc",
"webview/platform_views_rpc_instance.h",
"webview/web_content_controller.cc",
"webview/web_content_controller.h",
"webview/webview_controller.cc",
......@@ -392,6 +394,8 @@ cast_source_set("browser") {
"webview/webview_layout_manager.h",
"webview/webview_navigation_throttle.cc",
"webview/webview_navigation_throttle.h",
"webview/webview_rpc_instance.cc",
"webview/webview_rpc_instance.h",
"webview/webview_window_manager.cc",
"webview/webview_window_manager.h",
]
......
// Copyright 2019 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 "chromecast/browser/webview/platform_views_rpc_instance.h"
#include <deque>
#include <mutex>
#include "base/bind.h"
#include "base/single_thread_task_runner.h"
#include "chromecast/browser/webview/proto/webview.grpc.pb.h"
#include "chromecast/browser/webview/webview_window_manager.h"
#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
#include "third_party/grpc/src/include/grpcpp/security/server_credentials.h"
#include "third_party/grpc/src/include/grpcpp/server_builder.h"
namespace chromecast {
PlatformViewsRpcInstance::PlatformViewsRpcInstance(
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager)
: cq_(cq),
io_(&ctx_),
window_manager_(window_manager),
task_runner_(task_runner) {
write_options_.clear_buffer_hint();
write_options_.clear_corked();
init_callback_ = base::BindRepeating(&PlatformViewsRpcInstance::InitComplete,
base::Unretained(this));
read_callback_ = base::BindRepeating(&PlatformViewsRpcInstance::ReadComplete,
base::Unretained(this));
write_callback_ = base::BindRepeating(
&PlatformViewsRpcInstance::WriteComplete, base::Unretained(this));
destroy_callback_ = base::BindRepeating(
&PlatformViewsRpcInstance::FinishComplete, base::Unretained(this));
}
PlatformViewsRpcInstance::~PlatformViewsRpcInstance() {
DCHECK(destroying_);
if (controller_) {
controller_.release()->Destroy();
}
window_manager_->RemoveObserver(this);
}
void PlatformViewsRpcInstance::FinishComplete(bool ok) {
// Bounce off of the webview thread to allow it to complete any pending work.
destroying_ = true;
if (!send_pending_) {
task_runner_->DeleteSoon(FROM_HERE, this);
}
}
void PlatformViewsRpcInstance::ProcessRequestOnControllerThread(
std::unique_ptr<webview::WebviewRequest> request) {
controller_->ProcessRequest(*request.get());
}
void PlatformViewsRpcInstance::InitComplete(bool ok) {
if (!ok) {
destroying_ = true;
delete this;
return;
}
request_ = std::make_unique<webview::WebviewRequest>();
io_.Read(request_.get(), &read_callback_);
// Create a new instance to handle new requests.
// Instances of this class delete themselves.
CreateNewInstance();
}
void PlatformViewsRpcInstance::ReadComplete(bool ok) {
if (!ok) {
io_.Finish(grpc::Status(), &destroy_callback_);
} else if (controller_) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&PlatformViewsRpcInstance::ProcessRequestOnControllerThread,
base::Unretained(this), base::Passed(std::move(request_))));
request_ = std::make_unique<webview::WebviewRequest>();
std::unique_lock<std::mutex> l(send_lock_);
if (!errored_)
io_.Read(request_.get(), &read_callback_);
} else if (!Initialize()) {
io_.Finish(grpc::Status(grpc::FAILED_PRECONDITION, "Failed initialization"),
&destroy_callback_);
}
// In this case initialization is pending and the main webview thread will
// start the first read.
}
void PlatformViewsRpcInstance::WriteComplete(bool ok) {
std::unique_lock<std::mutex> l(send_lock_);
send_pending_ = false;
if (destroying_) {
// It is possible for the read & finish to complete while a write is
// outstanding, in that case just re-call it to delete this instance.
FinishComplete(true);
} else if (errored_) {
io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
} else if (!pending_messages_.empty()) {
send_pending_ = true;
io_.Write(*pending_messages_.front().get(), write_options_,
&write_callback_);
pending_messages_.pop_front();
}
}
void PlatformViewsRpcInstance::EnqueueSend(
std::unique_ptr<webview::WebviewResponse> response) {
std::unique_lock<std::mutex> l(send_lock_);
if (errored_ || destroying_)
return;
if (!send_pending_ && pending_messages_.empty()) {
send_pending_ = true;
io_.Write(*response.get(), write_options_, &write_callback_);
} else {
pending_messages_.emplace_back(std::move(response));
}
}
void PlatformViewsRpcInstance::OnError(const std::string& error_message) {
std::unique_lock<std::mutex> l(send_lock_);
errored_ = true;
error_message_ = error_message;
if (!send_pending_)
io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
send_pending_ = true;
}
void PlatformViewsRpcInstance::OnNewWebviewContainerWindow(aura::Window* window,
int app_id) {
if (app_id != app_id_)
return;
controller_->AttachTo(window, window_id_);
// The Webview is attached! No reason to keep on listening for window property
// updates.
window_manager_->RemoveObserver(this);
}
} // namespace chromecast
// Copyright 2019 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 CHROMECAST_BROWSER_WEBVIEW_PLATFORM_VIEWS_RPC_INSTANCE_H_
#define CHROMECAST_BROWSER_WEBVIEW_PLATFORM_VIEWS_RPC_INSTANCE_H_
#include <deque>
#include <mutex>
#include "base/callback.h"
#include "base/single_thread_task_runner.h"
#include "chromecast/browser/webview/proto/webview.grpc.pb.h"
#include "chromecast/browser/webview/web_content_controller.h"
#include "chromecast/browser/webview/webview_window_manager.h"
#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
#include "third_party/grpc/src/include/grpcpp/security/server_credentials.h"
#include "third_party/grpc/src/include/grpcpp/server_builder.h"
namespace chromecast {
typedef base::RepeatingCallback<void(bool)> GrpcCallback;
// Threading model and life cycle.
// PlatformViewsRpcInstance creates copies of itself and deletes itself as
// needed. Instances are deleted when the GRPC Finish request completes and
// there are no other outstanding read or write operations. Deletion bounces off
// the webview thread to synchronize with request processing.
class PlatformViewsRpcInstance : public WebContentController::Client,
public WebviewWindowManager::Observer {
public:
PlatformViewsRpcInstance(
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager);
~PlatformViewsRpcInstance() override;
protected:
virtual void CreateNewInstance() = 0;
virtual bool Initialize() = 0;
grpc::ServerContext ctx_;
grpc::ServerCompletionQueue* cq_;
std::unique_ptr<webview::WebviewRequest> request_;
grpc::ServerAsyncReaderWriter<webview::WebviewResponse,
webview::WebviewRequest>
io_;
std::unique_ptr<WebContentController> controller_;
GrpcCallback init_callback_;
GrpcCallback read_callback_;
WebviewWindowManager* window_manager_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Initialize to negative values since the aura::Window properties use 0 as
// the default value if the property isn't found.
int app_id_ = -1;
int window_id_ = -1;
private:
void InitComplete(bool ok);
void ReadComplete(bool ok);
void WriteComplete(bool ok);
void FinishComplete(bool ok);
void StartRead();
void CreateWebview(int app_id, int window_id);
void ProcessRequestOnControllerThread(
std::unique_ptr<webview::WebviewRequest> request);
// WebContentController::Client:
void EnqueueSend(std::unique_ptr<webview::WebviewResponse> response) override;
void OnError(const std::string& error_message) override;
// WebviewWindowManager::Observer:
void OnNewWebviewContainerWindow(aura::Window* window, int app_id) override;
GrpcCallback write_callback_;
GrpcCallback destroy_callback_;
std::mutex send_lock_;
bool errored_ = false;
std::string error_message_;
bool send_pending_ = false;
bool destroying_ = false;
std::deque<std::unique_ptr<webview::WebviewResponse>> pending_messages_;
grpc::WriteOptions write_options_;
DISALLOW_COPY_AND_ASSIGN(PlatformViewsRpcInstance);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_PLATFORM_VIEWS_RPC_INSTANCE_H_
......@@ -4,259 +4,13 @@
#include "chromecast/browser/webview/webview_grpc_service.h"
#include <deque>
#include <mutex>
#include "base/bind.h"
#include "base/callback.h"
#include "chromecast/browser/cast_browser_context.h"
#include "chromecast/browser/cast_browser_process.h"
#include "chromecast/browser/webview/webview_controller.h"
#include "chromecast/browser/webview/webview_rpc_instance.h"
#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
#include "third_party/grpc/src/include/grpcpp/security/server_credentials.h"
#include "third_party/grpc/src/include/grpcpp/server.h"
#include "third_party/grpc/src/include/grpcpp/server_builder.h"
namespace chromecast {
namespace {
typedef base::RepeatingCallback<void(bool)> GrpcCallback;
// Threading model and life cycle.
// WebviewRpcInstance creates copies of itself and deletes itself as needed.
// Instances are deleted when the GRPC Finish request completes and there are
// no other outstanding read or write operations.
// Deletion bounces off the webview thread to synchronize with request
// processing.
class WebviewRpcInstance : public WebviewController::Client,
public WebviewWindowManager::Observer {
public:
WebviewRpcInstance(webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager);
~WebviewRpcInstance() override;
private:
void InitComplete(bool ok);
void ReadComplete(bool ok);
void WriteComplete(bool ok);
void FinishComplete(bool ok);
bool Initialize();
void StartRead();
void CreateWebview(int app_id, int window_id);
void ProcessRequestOnWebviewThread(
std::unique_ptr<webview::WebviewRequest> request);
// WebviewController::Client:
void EnqueueSend(std::unique_ptr<webview::WebviewResponse> response) override;
void OnError(const std::string& error_message) override;
// WebviewWindowManager::Observer:
void OnNewWebviewContainerWindow(aura::Window* window, int app_id) override;
GrpcCallback init_callback_;
GrpcCallback read_callback_;
GrpcCallback write_callback_;
GrpcCallback destroy_callback_;
grpc::ServerContext ctx_;
webview::WebviewService::AsyncService* service_;
grpc::ServerCompletionQueue* cq_;
std::unique_ptr<webview::WebviewRequest> request_;
grpc::ServerAsyncReaderWriter<webview::WebviewResponse,
webview::WebviewRequest>
io_;
std::unique_ptr<WebviewController> webview_;
std::mutex send_lock_;
bool errored_ = false;
std::string error_message_;
bool send_pending_ = false;
bool destroying_ = false;
std::deque<std::unique_ptr<webview::WebviewResponse>> pending_messages_;
grpc::WriteOptions write_options_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
WebviewWindowManager* window_manager_;
// Initialize to negative values since the aura::Window properties use 0 as
// the default value if the property isn't found.
int app_id_ = -1;
int window_id_ = -1;
DISALLOW_COPY_AND_ASSIGN(WebviewRpcInstance);
};
WebviewRpcInstance::WebviewRpcInstance(
webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager)
: service_(service),
cq_(cq),
io_(&ctx_),
task_runner_(task_runner),
window_manager_(window_manager) {
write_options_.clear_buffer_hint();
write_options_.clear_corked();
init_callback_ = base::BindRepeating(&WebviewRpcInstance::InitComplete,
base::Unretained(this));
read_callback_ = base::BindRepeating(&WebviewRpcInstance::ReadComplete,
base::Unretained(this));
write_callback_ = base::BindRepeating(&WebviewRpcInstance::WriteComplete,
base::Unretained(this));
destroy_callback_ = base::BindRepeating(&WebviewRpcInstance::FinishComplete,
base::Unretained(this));
service_->RequestCreateWebview(&ctx_, &io_, cq_, cq_, &init_callback_);
}
WebviewRpcInstance::~WebviewRpcInstance() {
DCHECK(destroying_);
if (webview_) {
webview_.release()->Destroy();
}
window_manager_->RemoveObserver(this);
}
void WebviewRpcInstance::FinishComplete(bool ok) {
// Bounce off of the webview thread to allow it to complete any pending work.
destroying_ = true;
if (!send_pending_) {
task_runner_->DeleteSoon(FROM_HERE, this);
}
}
void WebviewRpcInstance::ProcessRequestOnWebviewThread(
std::unique_ptr<webview::WebviewRequest> request) {
webview_->ProcessRequest(*request.get());
}
void WebviewRpcInstance::InitComplete(bool ok) {
if (!ok) {
destroying_ = true;
delete this;
return;
}
request_ = std::make_unique<webview::WebviewRequest>();
io_.Read(request_.get(), &read_callback_);
// Create a new instance to handle new requests.
// Instances of this class delete themselves.
new WebviewRpcInstance(service_, cq_, task_runner_, window_manager_);
}
void WebviewRpcInstance::ReadComplete(bool ok) {
if (!ok) {
// Ensure we don't call finish twice.
if (!errored_)
io_.Finish(grpc::Status(), &destroy_callback_);
} else if (webview_) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&WebviewRpcInstance::ProcessRequestOnWebviewThread,
base::Unretained(this),
base::Passed(std::move(request_))));
request_ = std::make_unique<webview::WebviewRequest>();
std::unique_lock<std::mutex> l(send_lock_);
if (!errored_)
io_.Read(request_.get(), &read_callback_);
} else if (!Initialize()) {
io_.Finish(grpc::Status(grpc::FAILED_PRECONDITION, "Failed initialization"),
&destroy_callback_);
}
// In this case initialization is pending and the main webview thread will
// start the first read.
}
bool WebviewRpcInstance::Initialize() {
if (request_->type_case() != webview::WebviewRequest::kCreate)
return false;
// This needs to be done on a valid thread.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&WebviewRpcInstance::CreateWebview, base::Unretained(this),
request_->create().webview_id(),
request_->create().window_id()));
return true;
}
void WebviewRpcInstance::CreateWebview(int app_id, int window_id) {
app_id_ = app_id;
window_id_ = window_id;
// Only start listening for window events after the Webview is created. It
// doesn't make sense to listen before since there wouldn't be a Webview to
// parent.
window_manager_->AddObserver(this);
content::BrowserContext* browser_context =
shell::CastBrowserProcess::GetInstance()->browser_context();
webview_ = std::make_unique<WebviewController>(browser_context, this);
// Begin reading again.
io_.Read(request_.get(), &read_callback_);
}
void WebviewRpcInstance::WriteComplete(bool ok) {
std::unique_lock<std::mutex> l(send_lock_);
send_pending_ = false;
if (destroying_) {
// It is possible for the read & finish to complete while a write is
// outstanding, in that case just re-call it to delete this instance.
FinishComplete(true);
} else if (errored_) {
io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
} else if (!pending_messages_.empty()) {
send_pending_ = true;
io_.Write(*pending_messages_.front().get(), write_options_,
&write_callback_);
pending_messages_.pop_front();
}
}
void WebviewRpcInstance::EnqueueSend(
std::unique_ptr<webview::WebviewResponse> response) {
std::unique_lock<std::mutex> l(send_lock_);
if (errored_ || destroying_)
return;
if (!send_pending_ && pending_messages_.empty()) {
send_pending_ = true;
io_.Write(*response.get(), write_options_, &write_callback_);
} else {
pending_messages_.emplace_back(std::move(response));
}
}
void WebviewRpcInstance::OnError(const std::string& error_message) {
std::unique_lock<std::mutex> l(send_lock_);
errored_ = true;
error_message_ = error_message;
if (!send_pending_)
io_.Finish(grpc::Status(grpc::UNKNOWN, error_message_), &destroy_callback_);
send_pending_ = true;
}
void WebviewRpcInstance::OnNewWebviewContainerWindow(aura::Window* window,
int app_id) {
if (app_id != app_id_)
return;
webview_->AttachTo(window, window_id_);
// The Webview is attached! No reason to keep on listening for window property
// updates.
window_manager_->RemoveObserver(this);
}
} // namespace
WebviewAsyncService::WebviewAsyncService(
std::unique_ptr<webview::WebviewService::AsyncService> service,
......
// Copyright 2019 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 "chromecast/browser/webview/webview_rpc_instance.h"
#include "base/bind.h"
#include "base/callback.h"
#include "chromecast/browser/cast_browser_context.h"
#include "chromecast/browser/cast_browser_process.h"
#include "chromecast/browser/webview/platform_views_rpc_instance.h"
#include "chromecast/browser/webview/webview_controller.h"
#include "third_party/grpc/src/include/grpcpp/grpcpp.h"
#include "third_party/grpc/src/include/grpcpp/security/server_credentials.h"
#include "third_party/grpc/src/include/grpcpp/server.h"
#include "third_party/grpc/src/include/grpcpp/server_builder.h"
namespace chromecast {
WebviewRpcInstance::WebviewRpcInstance(
webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager)
: PlatformViewsRpcInstance(cq, task_runner, window_manager),
service_(service) {
service_->RequestCreateWebview(&ctx_, &io_, cq_, cq_, &init_callback_);
}
WebviewRpcInstance::~WebviewRpcInstance() {}
void WebviewRpcInstance::CreateNewInstance() {
new WebviewRpcInstance(service_, cq_, task_runner_, window_manager_);
}
bool WebviewRpcInstance::Initialize() {
if (request_->type_case() != webview::WebviewRequest::kCreate)
return false;
// This needs to be done on a valid thread.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&WebviewRpcInstance::CreateWebview, base::Unretained(this),
request_->create().webview_id(),
request_->create().window_id()));
return true;
}
void WebviewRpcInstance::CreateWebview(int app_id, int window_id) {
app_id_ = app_id;
window_id_ = window_id;
// Only start listening for window events after the Webview is created. It
// doesn't make sense to listen before since there wouldn't be a Webview to
// parent.
window_manager_->AddObserver(this);
content::BrowserContext* browser_context =
shell::CastBrowserProcess::GetInstance()->browser_context();
controller_ = std::make_unique<WebviewController>(browser_context, this);
// Begin reading again.
io_.Read(request_.get(), &read_callback_);
}
} // namespace chromecast
// Copyright 2019 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 CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_RPC_INSTANCE_H_
#define CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_RPC_INSTANCE_H_
#include "chromecast/browser/webview/platform_views_rpc_instance.h"
namespace chromecast {
class WebviewRpcInstance : public PlatformViewsRpcInstance {
public:
WebviewRpcInstance(webview::WebviewService::AsyncService* service,
grpc::ServerCompletionQueue* cq,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
WebviewWindowManager* window_manager);
~WebviewRpcInstance() override;
protected:
void CreateNewInstance() override;
bool Initialize() override;
private:
void CreateWebview(int app_id, int window_id);
webview::WebviewService::AsyncService* service_;
DISALLOW_COPY_AND_ASSIGN(WebviewRpcInstance);
};
} // namespace chromecast
#endif // CHROMECAST_BROWSER_WEBVIEW_WEBVIEW_RPC_INSTANCE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment