[Chromecast] Add support for dynamic browser lifecycle
This change enables the standalone Cast Browser to start/stop independently of the Cast Service. The following changes were made: * Moved BrokerService from the Cast Browser to Cast Service. * Introduced ReconnectingRemote, which silently handles Mojo reconnects. Optionally, users can opt-in to receive reconnect events so that they can properly re-initialize certain system states. Merge-With: eureka-internal/707435 Bug: b/213495969 Test: Build/run cast_service + cast_browser, start/stop cast_browser and verify backdrop restarts. Change-Id: I32a84972e7fa282cd6276115e6fe6ac323b5f4c2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3385361 Reviewed-by: Junbo Ke <juke@chromium.org> Commit-Queue: Sean Topping <seantopping@chromium.org> Cr-Commit-Position: refs/heads/main@{#961100}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
5ac7a871bf
commit
83574b3e03
chromecast
base
browser
external_mojo
@ -228,6 +228,10 @@ const char kDeferFeatureList[] = "defer-feature-list";
|
||||
// running in a different process from `cast_service`.
|
||||
const char kUseCastBrowserPrefConfig[] = "use-cast-browser-pref-config";
|
||||
|
||||
// Creates the service broker inside of this process. Only one process should
|
||||
// host the service broker.
|
||||
const char kInProcessBroker[] = "in-process-broker";
|
||||
|
||||
} // namespace switches
|
||||
|
||||
namespace chromecast {
|
||||
|
@ -108,6 +108,7 @@ extern const char kExtensionsDir[];
|
||||
// Switches for Cast browser decoupling.
|
||||
extern const char kDeferFeatureList[];
|
||||
extern const char kUseCastBrowserPrefConfig[];
|
||||
extern const char kInProcessBroker[];
|
||||
|
||||
} // namespace switches
|
||||
|
||||
|
@ -234,6 +234,8 @@ cast_source_set("browser_base") {
|
||||
"//chromecast/common/media",
|
||||
"//chromecast/external_mojo/broker_service",
|
||||
"//chromecast/external_mojo/external_service_support:external_service",
|
||||
"//chromecast/external_mojo/external_service_support:util",
|
||||
"//chromecast/external_mojo/public/cpp:common",
|
||||
"//chromecast/graphics",
|
||||
"//chromecast/media",
|
||||
"//chromecast/media:libcast_media",
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "chromecast/external_mojo/broker_service/broker_service.h"
|
||||
#include "chromecast/external_mojo/external_service_support/external_connector.h"
|
||||
#include "chromecast/external_mojo/external_service_support/external_service.h"
|
||||
#include "chromecast/external_mojo/public/cpp/common.h"
|
||||
#include "chromecast/graphics/cast_window_manager.h"
|
||||
#include "chromecast/media/base/key_systems_common.h"
|
||||
#include "chromecast/media/base/video_plane_controller.h"
|
||||
@ -559,12 +560,17 @@ int CastBrowserMainParts::PreCreateThreads() {
|
||||
}
|
||||
|
||||
void CastBrowserMainParts::PostCreateThreads() {
|
||||
auto* service_manager_connector =
|
||||
ServiceManagerConnection::GetForProcess()->GetConnector();
|
||||
broker_service_ =
|
||||
std::make_unique<external_mojo::BrokerService>(service_manager_connector);
|
||||
connector_ = external_service_support::ExternalConnector::Create(
|
||||
broker_service_->CreateConnector());
|
||||
if (GetSwitchValueBoolean(switches::kInProcessBroker, true)) {
|
||||
auto* service_manager_connector =
|
||||
ServiceManagerConnection::GetForProcess()->GetConnector();
|
||||
broker_service_ = std::make_unique<external_mojo::BrokerService>(
|
||||
service_manager_connector);
|
||||
connector_ = external_service_support::ExternalConnector::Create(
|
||||
broker_service_->CreateConnector());
|
||||
} else {
|
||||
connector_ = external_service_support::ExternalConnector::Create(
|
||||
external_mojo::GetBrokerPath());
|
||||
}
|
||||
media_connector_ = connector_->Clone();
|
||||
browser_service_ =
|
||||
std::make_unique<external_service_support::ExternalService>();
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "chromecast/browser/mojom/cast_web_service.mojom.h"
|
||||
#include "chromecast/common/identification_settings_manager.h"
|
||||
#include "chromecast/common/mojom/identification_settings.mojom.h"
|
||||
#include "chromecast/external_mojo/external_service_support/reconnecting_remote.h"
|
||||
#include "mojo/public/cpp/bindings/pending_remote.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
@ -69,6 +70,7 @@ class CastWebService : public mojom::CastWebService,
|
||||
LRURendererCache* overlay_renderer_cache() {
|
||||
return overlay_renderer_cache_.get();
|
||||
}
|
||||
ReconnectingRemote<mojom::CastWebService>* proxy() { return &proxy_; }
|
||||
|
||||
bool IsCastWebUIOrigin(const url::Origin& origin);
|
||||
|
||||
@ -118,6 +120,12 @@ class CastWebService : public mojom::CastWebService,
|
||||
content::BrowserContext* const browser_context_;
|
||||
// This is used on Aura platforms.
|
||||
CastWindowManager* const window_manager_;
|
||||
|
||||
// This is injected into clients which live in the browser or in a remote
|
||||
// process. This is temporary until the clients exclusively live in an
|
||||
// external process.
|
||||
ReconnectingRemote<mojom::CastWebService> proxy_{this};
|
||||
|
||||
CastWebViewFactory default_web_view_factory_;
|
||||
|
||||
CastWebViewFactory* override_web_view_factory_ = nullptr;
|
||||
|
@ -123,7 +123,9 @@ source_set("standalone_service_main") {
|
||||
":process_setup",
|
||||
":tracing_client",
|
||||
"//base",
|
||||
"//chromecast/base:chromecast_switches",
|
||||
"//chromecast/external_mojo/public/cpp:common",
|
||||
"//chromecast/external_mojo/public/cpp:external_mojo_broker",
|
||||
"//mojo/core/embedder",
|
||||
]
|
||||
public_deps = [ ":service_process" ]
|
||||
@ -144,6 +146,15 @@ source_set("chromium_service") {
|
||||
]
|
||||
}
|
||||
|
||||
source_set("util") {
|
||||
public = [ "reconnecting_remote.h" ]
|
||||
public_deps = [
|
||||
":external_service",
|
||||
"//base",
|
||||
"//mojo/public/cpp/bindings",
|
||||
]
|
||||
}
|
||||
|
||||
executable("standalone_mojo_broker") {
|
||||
sources = [ "standalone_mojo_broker.cc" ]
|
||||
deps = [
|
||||
|
@ -103,6 +103,11 @@ class ExternalConnector {
|
||||
// sequence.
|
||||
virtual std::unique_ptr<ExternalConnector> Clone() = 0;
|
||||
|
||||
// Requests a PendingRemote for an ExternalConnector which can be passed to a
|
||||
// different process.
|
||||
virtual mojo::PendingRemote<external_mojo::mojom::ExternalConnector>
|
||||
RequestConnector() = 0;
|
||||
|
||||
// Sends a request for a Chromium ServiceManager connector.
|
||||
virtual void SendChromiumConnectorRequest(
|
||||
mojo::ScopedMessagePipeHandle request) = 0;
|
||||
|
@ -265,11 +265,18 @@ std::unique_ptr<ExternalConnector> ExternalConnectorImpl::Clone() {
|
||||
if (broker_connection_) {
|
||||
return std::make_unique<ExternalConnectorImpl>(broker_connection_);
|
||||
}
|
||||
// Bind to the current sequence since this is a public method.
|
||||
BindConnectorIfNecessary();
|
||||
return std::make_unique<ExternalConnectorImpl>(RequestConnector());
|
||||
}
|
||||
|
||||
mojo::PendingRemote<external_mojo::mojom::ExternalConnector>
|
||||
ExternalConnectorImpl::RequestConnector() {
|
||||
// Bind to the current sequence since this is a public method.
|
||||
BindConnectorIfNecessary();
|
||||
mojo::PendingRemote<external_mojo::mojom::ExternalConnector> remote;
|
||||
connector_->Clone(remote.InitWithNewPipeAndPassReceiver());
|
||||
return std::make_unique<ExternalConnectorImpl>(std::move(remote));
|
||||
return remote;
|
||||
}
|
||||
|
||||
void ExternalConnectorImpl::SendChromiumConnectorRequest(
|
||||
|
@ -56,6 +56,8 @@ class ExternalConnectorImpl : public ExternalConnector {
|
||||
mojo::ScopedMessagePipeHandle interface_pipe,
|
||||
bool async = true) override;
|
||||
std::unique_ptr<ExternalConnector> Clone() override;
|
||||
mojo::PendingRemote<external_mojo::mojom::ExternalConnector>
|
||||
RequestConnector() override;
|
||||
void SendChromiumConnectorRequest(
|
||||
mojo::ScopedMessagePipeHandle request) override;
|
||||
void QueryServiceList(
|
||||
|
@ -87,6 +87,11 @@ FakeExternalConnector::Clone() {
|
||||
return std::make_unique<FakeExternalConnector>(std::move(remote));
|
||||
}
|
||||
|
||||
mojo::PendingRemote<external_mojo::mojom::ExternalConnector>
|
||||
FakeExternalConnector::RequestConnector() {
|
||||
return mojo::PendingRemote<external_mojo::mojom::ExternalConnector>();
|
||||
}
|
||||
|
||||
void FakeExternalConnector::SendChromiumConnectorRequest(
|
||||
mojo::ScopedMessagePipeHandle request) {}
|
||||
|
||||
|
@ -54,6 +54,8 @@ class FakeExternalConnector
|
||||
std::vector<chromecast::external_mojo::mojom::ServiceInstanceInfoPtr>
|
||||
service_instances_info) override;
|
||||
std::unique_ptr<external_service_support::ExternalConnector> Clone() override;
|
||||
mojo::PendingRemote<external_mojo::mojom::ExternalConnector>
|
||||
RequestConnector() override;
|
||||
void SendChromiumConnectorRequest(
|
||||
mojo::ScopedMessagePipeHandle request) override;
|
||||
void QueryServiceList(
|
||||
|
@ -0,0 +1,112 @@
|
||||
// Copyright 2022 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_EXTERNAL_MOJO_EXTERNAL_SERVICE_SUPPORT_RECONNECTING_REMOTE_H_
|
||||
#define CHROMECAST_EXTERNAL_MOJO_EXTERNAL_SERVICE_SUPPORT_RECONNECTING_REMOTE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/callback.h"
|
||||
#include "base/check.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "chromecast/external_mojo/external_service_support/external_connector.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
|
||||
namespace chromecast {
|
||||
|
||||
// A class which wraps a mojo::Remote with automatic reconnection logic.
|
||||
//
|
||||
// Two reconnection methods are supported: (1) Provide a service name and an
|
||||
// ExternalConnector to reconnect, or (2) provide a callback to rebind the
|
||||
// remote.
|
||||
//
|
||||
// Clients can register observer callbacks to be notified of reconnect events so
|
||||
// that they can re-initialize some state in the remote process. Observers are
|
||||
// notified in the same order they were registered. Observers should use WeakPtr
|
||||
// if they expect to outlive the ReconnectingRemote.
|
||||
//
|
||||
// This class can also be used to wrap a local implementation. This can be used
|
||||
// for (1) Client code which can exist in both in and out-of-process, and (2)
|
||||
// Injecting a mock implementation. Since the impl is called directly, this
|
||||
// allows for synchronous method call validation, as opposed to asynchronously
|
||||
// posting mojo calls which require a base::RunLoop to verify in unit tests.
|
||||
//
|
||||
template <typename Interface>
|
||||
class ReconnectingRemote {
|
||||
public:
|
||||
// Reconnect option 1: Provide an ExternalConnector to request the interface
|
||||
// from a named service.
|
||||
ReconnectingRemote(const std::string& service_name,
|
||||
external_service_support::ExternalConnector* connector)
|
||||
: service_name_(service_name), connector_(connector) {
|
||||
DCHECK(connector_);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Reconnect option 2: Provide a callback to re-bind |remote_|. |remote_| is
|
||||
// always in an unbound state before |connect_callback_| is run.
|
||||
explicit ReconnectingRemote(
|
||||
base::RepeatingCallback<void(mojo::Remote<Interface>* remote)>
|
||||
connect_callback)
|
||||
: connect_callback_(std::move(connect_callback)) {
|
||||
Connect();
|
||||
}
|
||||
|
||||
// Option 3: Inject an implementation directly to wrap a local implementation.
|
||||
// Reconnection is not necessary since a local instance will always exist.
|
||||
explicit ReconnectingRemote(Interface* impl) : remote_proxy_(impl) {}
|
||||
|
||||
ReconnectingRemote(const ReconnectingRemote&) = delete;
|
||||
ReconnectingRemote& operator=(const ReconnectingRemote&) = delete;
|
||||
~ReconnectingRemote() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
|
||||
|
||||
Interface* get() const { return remote_proxy_; }
|
||||
Interface* operator->() const { return get(); }
|
||||
Interface& operator*() const { return *get(); }
|
||||
|
||||
void OnReconnect(base::RepeatingClosure callback) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
observer_callbacks_.push_back(std::move(callback));
|
||||
}
|
||||
|
||||
private:
|
||||
void Connect() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
remote_.reset();
|
||||
if (connector_) {
|
||||
connector_->BindInterface(service_name_,
|
||||
remote_.BindNewPipeAndPassReceiver());
|
||||
} else {
|
||||
connect_callback_.Run(&remote_);
|
||||
}
|
||||
DCHECK(remote_.is_bound());
|
||||
remote_proxy_ = remote_.get();
|
||||
remote_.set_disconnect_handler(
|
||||
base::BindOnce(&ReconnectingRemote::Connect, base::Unretained(this)));
|
||||
for (auto& callback : observer_callbacks_) {
|
||||
callback.Run();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string service_name_;
|
||||
external_service_support::ExternalConnector* const connector_ = nullptr;
|
||||
|
||||
base::RepeatingCallback<void(mojo::Remote<Interface>* remote)>
|
||||
connect_callback_;
|
||||
|
||||
mojo::Remote<Interface> remote_;
|
||||
Interface* remote_proxy_ = nullptr;
|
||||
std::vector<base::RepeatingClosure> observer_callbacks_;
|
||||
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
base::WeakPtrFactory<ReconnectingRemote> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace chromecast
|
||||
#endif // CHROMECAST_EXTERNAL_MOJO_EXTERNAL_SERVICE_SUPPORT_RECONNECTING_REMOTE_H_
|
@ -7,18 +7,24 @@
|
||||
|
||||
#include "base/at_exit.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/message_loop/message_pump_for_io.h"
|
||||
#include "base/message_loop/message_pump_type.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/task/single_thread_task_executor.h"
|
||||
#include "base/task/thread_pool/thread_pool_instance.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "chromecast/base/chromecast_switches.h"
|
||||
#include "chromecast/external_mojo/external_service_support/external_connector.h"
|
||||
#include "chromecast/external_mojo/external_service_support/process_setup.h"
|
||||
#include "chromecast/external_mojo/external_service_support/service_process.h"
|
||||
#include "chromecast/external_mojo/external_service_support/tracing_client.h"
|
||||
#include "chromecast/external_mojo/public/cpp/common.h"
|
||||
#include "chromecast/external_mojo/public/cpp/external_mojo_broker.h"
|
||||
#include "mojo/core/embedder/embedder.h"
|
||||
#include "mojo/core/embedder/scoped_ipc_support.h"
|
||||
#include "mojo/public/cpp/bindings/pending_remote.h"
|
||||
|
||||
// Simple process entrypoint for standalone Mojo services.
|
||||
|
||||
@ -61,9 +67,32 @@ int main(int argc, char** argv) {
|
||||
"StandaloneService");
|
||||
|
||||
GlobalState state;
|
||||
chromecast::external_service_support::ExternalConnector::Connect(
|
||||
chromecast::external_mojo::GetBrokerPath(),
|
||||
base::BindOnce(&OnConnected, &state));
|
||||
// State for in-process Mojo broker.
|
||||
auto broker_thread = std::make_unique<base::Thread>("external_mojo");
|
||||
base::SequenceBound<chromecast::external_mojo::ExternalMojoBroker> broker;
|
||||
|
||||
if (chromecast::GetSwitchValueBoolean(switches::kInProcessBroker, false)) {
|
||||
// Set up the external Mojo Broker.
|
||||
broker_thread->StartWithOptions(
|
||||
base::Thread::Options(base::MessagePumpType::IO, 0));
|
||||
broker = base::SequenceBound<chromecast::external_mojo::ExternalMojoBroker>(
|
||||
broker_thread->task_runner(),
|
||||
chromecast::external_mojo::GetBrokerPath());
|
||||
mojo::PendingRemote<chromecast::external_mojo::mojom::ExternalConnector>
|
||||
connector_remote;
|
||||
broker
|
||||
.AsyncCall(
|
||||
&chromecast::external_mojo::ExternalMojoBroker::BindConnector)
|
||||
.WithArgs(connector_remote.InitWithNewPipeAndPassReceiver());
|
||||
OnConnected(&state,
|
||||
chromecast::external_service_support::ExternalConnector::Create(
|
||||
std::move(connector_remote)));
|
||||
} else {
|
||||
// Connect to existing Mojo broker.
|
||||
chromecast::external_service_support::ExternalConnector::Connect(
|
||||
chromecast::external_mojo::GetBrokerPath(),
|
||||
base::BindOnce(&OnConnected, &state));
|
||||
}
|
||||
|
||||
run_loop.Run();
|
||||
base::ThreadPoolInstance::Get()->Shutdown();
|
||||
|
Reference in New Issue
Block a user