Commit bc1f34b9 authored by Xiaohan Wang's avatar Xiaohan Wang Committed by Commit Bot

media: Support hosting mojo CDM in a standalone service

Currently when mojo CDM is enabled it is hosted in the MediaService
running in the process specified by "mojo_media_host". However, on
some platforms we need to run mojo CDM and other mojo media services in
different processes. For example, on desktop platforms, we want to run
mojo video decoder in the GPU process, but run the mojo CDM in the
utility process.

This CL adds a new build flag "enable_standalone_cdm_service". When
enabled, the mojo CDM service will be hosted in a standalone "cdm"
service running in the utility process. All other mojo media services
will sill be hosted in the "media" servie running in the process
specified by "mojo_media_host".

BUG=664364
TEST=Encrypted media browser tests using mojo CDM is still working.

Change-Id: I95be6e05adc9ebcff966b26958ef1d7becdfb487
Reviewed-on: https://chromium-review.googlesource.com/567172
Commit-Queue: Xiaohan Wang <xhwang@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486947}
parent e6af5cab
......@@ -12,7 +12,6 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_client.h"
#include "content/public/common/service_manager_connection.h"
#include "media/mojo/features.h"
#include "media/mojo/interfaces/constants.mojom.h"
#include "media/mojo/interfaces/media_service.mojom.h"
#include "media/mojo/services/media_interface_provider.h"
......@@ -72,7 +71,7 @@ void MediaInterfaceProxy::CreateRenderer(
void MediaInterfaceProxy::CreateCdm(
media::mojom::ContentDecryptionModuleRequest request) {
DCHECK(thread_checker_.CalledOnValidThread());
GetMediaInterfaceFactory()->CreateCdm(std::move(request));
GetCdmInterfaceFactory()->CreateCdm(std::move(request));
}
media::mojom::InterfaceFactory*
......@@ -81,31 +80,52 @@ MediaInterfaceProxy::GetMediaInterfaceFactory() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!interface_factory_ptr_)
ConnectToService();
ConnectToMediaService();
DCHECK(interface_factory_ptr_);
return interface_factory_ptr_.get();
}
void MediaInterfaceProxy::OnConnectionError() {
media::mojom::InterfaceFactory* MediaInterfaceProxy::GetCdmInterfaceFactory() {
DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
#if !BUILDFLAG(ENABLE_STANDALONE_CDM_SERVICE)
return GetMediaInterfaceFactory();
#else
if (!cdm_interface_factory_ptr_)
ConnectToCdmService();
DCHECK(cdm_interface_factory_ptr_);
return cdm_interface_factory_ptr_.get();
#endif
}
void MediaInterfaceProxy::OnMediaServiceConnectionError() {
DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
interface_factory_ptr_.reset();
}
void MediaInterfaceProxy::ConnectToService() {
void MediaInterfaceProxy::OnCdmServiceConnectionError() {
DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!interface_factory_ptr_);
cdm_interface_factory_ptr_.reset();
}
service_manager::mojom::InterfaceProviderPtr
MediaInterfaceProxy::GetFrameServices() {
// Register frame services.
service_manager::mojom::InterfaceProviderPtr interfaces;
// TODO(xhwang): Replace this InterfaceProvider with a dedicated media host
// interface. See http://crbug.com/660573
auto provider = base::MakeUnique<media::MediaInterfaceProvider>(
mojo::MakeRequest(&interfaces));
#if BUILDFLAG(ENABLE_MOJO_CDM)
// TODO(slan): Wrap these into a RenderFrame specific ProvisionFetcher impl.
net::URLRequestContextGetter* context_getter =
......@@ -115,20 +135,49 @@ void MediaInterfaceProxy::ConnectToService() {
provider->registry()->AddInterface(base::Bind(
&ProvisionFetcherImpl::Create, base::RetainedRef(context_getter)));
#endif // BUILDFLAG(ENABLE_MOJO_CDM)
GetContentClient()->browser()->ExposeInterfacesToMediaService(
provider->registry(), render_frame_host_);
media_registries_.push_back(std::move(provider));
// TODO(slan): Use the BrowserContext Connector instead. See crbug.com/638950.
return interfaces;
}
void MediaInterfaceProxy::ConnectToMediaService() {
DVLOG(1) << __FUNCTION__;
media::mojom::MediaServicePtr media_service;
// TODO(slan): Use the BrowserContext Connector instead. See crbug.com/638950.
service_manager::Connector* connector =
ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(media::mojom::kMediaServiceName, &media_service);
media_service->CreateInterfaceFactory(MakeRequest(&interface_factory_ptr_),
std::move(interfaces));
interface_factory_ptr_.set_connection_error_handler(base::Bind(
&MediaInterfaceProxy::OnConnectionError, base::Unretained(this)));
GetFrameServices());
interface_factory_ptr_.set_connection_error_handler(
base::Bind(&MediaInterfaceProxy::OnMediaServiceConnectionError,
base::Unretained(this)));
}
void MediaInterfaceProxy::ConnectToCdmService() {
DVLOG(1) << __FUNCTION__;
media::mojom::MediaServicePtr media_service;
// TODO(slan): Use the BrowserContext Connector instead. See crbug.com/638950.
service_manager::Connector* connector =
ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(media::mojom::kCdmServiceName, &media_service);
media_service->CreateInterfaceFactory(
MakeRequest(&cdm_interface_factory_ptr_), GetFrameServices());
cdm_interface_factory_ptr_.set_connection_error_handler(
base::Bind(&MediaInterfaceProxy::OnCdmServiceConnectionError,
base::Unretained(this)));
}
} // namespace content
......@@ -10,8 +10,10 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "media/mojo/features.h"
#include "media/mojo/interfaces/interface_factory.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
namespace media {
class MediaInterfaceProvider;
......@@ -27,8 +29,8 @@ class RenderFrameHost;
class MediaInterfaceProxy : public media::mojom::InterfaceFactory {
public:
// Constructs MediaInterfaceProxy and bind |this| to the |request|. When
// connection error happens on the client interface, |error_handler| should be
// fired.
// connection error happens on the client interface, |error_handler| will be
// called, which could destroy |this|.
MediaInterfaceProxy(RenderFrameHost* render_frame_host,
media::mojom::InterfaceFactoryRequest request,
const base::Closure& error_handler);
......@@ -42,12 +44,21 @@ class MediaInterfaceProxy : public media::mojom::InterfaceFactory {
void CreateCdm(media::mojom::ContentDecryptionModuleRequest request) final;
private:
// Get the |interface_factory_ptr_|.
media::mojom::InterfaceFactory* GetMediaInterfaceFactory();
// Callback for connection error on |interface_factory_ptr_|.
void OnConnectionError();
// Get the |cdm_interface_factory_ptr_|.
media::mojom::InterfaceFactory* GetCdmInterfaceFactory();
void ConnectToService();
// Callback for connection error from |interface_factory_ptr_| or
// |cdm_interface_factory_ptr_|.
void OnMediaServiceConnectionError();
void OnCdmServiceConnectionError();
service_manager::mojom::InterfaceProviderPtr GetFrameServices();
void ConnectToMediaService();
void ConnectToCdmService();
// Safe to hold a raw pointer since |this| is owned by RenderFrameHostImpl.
RenderFrameHost* render_frame_host_;
......@@ -58,9 +69,16 @@ class MediaInterfaceProxy : public media::mojom::InterfaceFactory {
mojo::Binding<media::mojom::InterfaceFactory> binding_;
// InterfacePtr to the remote media::mojom::InterfaceFactory implementation.
// InterfacePtr to the remote media::mojom::InterfaceFactory implementation
// in the service named kMediaServiceName hosted in the process specified by
// the "mojo_media_host" gn argument. Available options are browser, GPU and
// utility processes.
media::mojom::InterfaceFactoryPtr interface_factory_ptr_;
// InterfacePtr to the remote media::mojom::InterfaceFactory implementation
// in the service named kCdmServiceName hosted in the utility process.
media::mojom::InterfaceFactoryPtr cdm_interface_factory_ptr_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(MediaInterfaceProxy);
......
......@@ -357,11 +357,17 @@ ServiceManagerContext::ServiceManagerContext() {
}
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS)
out_of_process_services[media::mojom::kMediaServiceName] = {
base::ASCIIToUTF16("Media Service"), SANDBOX_TYPE_UTILITY};
#endif
#if BUILDFLAG(ENABLE_STANDALONE_CDM_SERVICE)
// TODO(xhwang): This is only used for test/experiment for now so it's okay
// to run it in an unsandboxed utility process. Fix CDM loading so that we can
// run it in the sandboxed utility process. See http://crbug.com/510604
out_of_process_services[media::mojom::kMediaServiceName] = {
base::ASCIIToUTF16("Media Service"), SANDBOX_TYPE_NO_SANDBOX};
out_of_process_services[media::mojom::kCdmServiceName] = {
base::ASCIIToUTF16("Content Decryption Module Service"),
SANDBOX_TYPE_NO_SANDBOX};
#endif
for (const auto& service : out_of_process_services) {
......
......@@ -238,7 +238,8 @@ class ServiceManagerConnectionImpl::IOThreadContext
const ServiceRequestHandler& handler) {
DCHECK(io_thread_checker_.CalledOnValidThread());
auto result = request_handlers_.insert(std::make_pair(name, handler));
DCHECK(result.second);
DCHECK(result.second) << "ServiceRequestHandler for " << name
<< " already exists.";
}
/////////////////////////////////////////////////////////////////////////////
......
......@@ -182,6 +182,7 @@ service_manifest("packaged_services_manifest") {
source = "mojo/content_packaged_services_manifest.json"
packaged_services = [
"//content/network:manifest",
"//media/mojo/services:cdm_manifest",
"//media/mojo/services:media_manifest",
"//services/data_decoder:manifest",
"//services/device:manifest",
......
......@@ -60,6 +60,7 @@
},
"requires": {
"*": [ "app" ],
"cdm": [ "media:cdm" ],
// In classic ash, the browser supplies ash interfaces to itself.
"content_browser": [
"ash",
......
......@@ -47,7 +47,7 @@ namespace {
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
static_assert(BUILDFLAG(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS), "");
static_assert(BUILDFLAG(ENABLE_STANDALONE_CDM_SERVICE), "");
static_assert(BUILDFLAG(ENABLE_MOJO_CDM), "");
std::unique_ptr<media::CdmAllocator> CreateCdmAllocator() {
......@@ -66,7 +66,7 @@ class CdmMojoMediaClient final : public media::MojoMediaClient {
}
};
std::unique_ptr<service_manager::Service> CreateMediaService() {
std::unique_ptr<service_manager::Service> CreateCdmService() {
return std::unique_ptr<service_manager::Service>(
new ::media::MediaService(base::MakeUnique<CdmMojoMediaClient>()));
}
......@@ -94,8 +94,8 @@ void UtilityServiceFactory::RegisterServices(ServiceMap* services) {
#if BUILDFLAG(ENABLE_PEPPER_CDMS)
service_manager::EmbeddedServiceInfo info;
info.factory = base::Bind(&CreateMediaService);
services->insert(std::make_pair(media::mojom::kMediaServiceName, info));
info.factory = base::Bind(&CreateCdmService);
services->insert(std::make_pair(media::mojom::kCdmServiceName, info));
#endif
service_manager::EmbeddedServiceInfo shape_detection_info;
......
......@@ -149,6 +149,11 @@ declare_args() {
# - "utility": Use mojo media service hosted in the utility process.
mojo_media_host = "none"
# Force to host the CDM service in standalone "cdm" service instead of the
# "media" service hosted in the process specified by "mojo_media_host". Other
# mojo media services will not be affected.
enable_standalone_cdm_service = false
# Default mojo_media_services and mojo_media_host on various platforms.
# Can be overridden by gn build arguments from the --args command line flag
# for local testing.
......@@ -167,10 +172,8 @@ declare_args() {
]
mojo_media_host = "gpu"
} else if (enable_pepper_cdms) {
# TODO(xhwang): Also support running "video_decoder" service in the "gpu"
# process. See http://crbug.com/664364
mojo_media_services = [ "cdm" ]
mojo_media_host = "utility"
enable_standalone_cdm_service = true
}
}
}
......
......@@ -46,11 +46,16 @@ buildflag_header("features") {
enable_mojo_media_in_gpu_process = true
} else if (mojo_media_host == "utility") {
enable_mojo_media_in_utility_process = true
} else {
} else if (!enable_standalone_cdm_service) {
assert(false, "Invalid mojo media host: $mojo_media_host")
}
}
if (enable_standalone_cdm_service) {
assert(enable_mojo_cdm,
"Mojo CDM must be enabled to run in standalone CDM service.")
}
flags = [
"ENABLE_MOJO_MEDIA=$enable_mojo_media",
"ENABLE_TEST_MOJO_MEDIA_CLIENT=$enable_test_mojo_media_client",
......@@ -61,6 +66,7 @@ buildflag_header("features") {
"ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS=$enable_mojo_media_in_browser_process",
"ENABLE_MOJO_MEDIA_IN_GPU_PROCESS=$enable_mojo_media_in_gpu_process",
"ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS=$enable_mojo_media_in_utility_process",
"ENABLE_STANDALONE_CDM_SERVICE=$enable_standalone_cdm_service",
]
}
......
......@@ -8,3 +8,7 @@ module media.mojom;
// the |mojo_media_host| gn variable. This must match the name in
// media/mojo/services/media_manifest.json
const string kMediaServiceName = "media";
// The default service name for MediaService hosting only the CDM service.
// This must match the name in media/mojo/services/cdm_manifest.json
const string kCdmServiceName = "cdm";
......@@ -140,6 +140,11 @@ service_test("media_service_unittests") {
]
}
service_manifest("cdm_manifest") {
name = "cdm"
source = "cdm_manifest.json"
}
service_manifest("media_manifest") {
name = "media"
source = "media_manifest.json"
......
{
"name": "cdm",
"display_name": "Content Decryption Module Service",
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
"media:cdm": [ "media::mojom::MediaService" ]
},
"requires": {
"*": [ "app" ]
}
}
}
}
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