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 @@ ...@@ -12,7 +12,6 @@
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/common/content_client.h" #include "content/public/common/content_client.h"
#include "content/public/common/service_manager_connection.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/constants.mojom.h"
#include "media/mojo/interfaces/media_service.mojom.h" #include "media/mojo/interfaces/media_service.mojom.h"
#include "media/mojo/services/media_interface_provider.h" #include "media/mojo/services/media_interface_provider.h"
...@@ -72,7 +71,7 @@ void MediaInterfaceProxy::CreateRenderer( ...@@ -72,7 +71,7 @@ void MediaInterfaceProxy::CreateRenderer(
void MediaInterfaceProxy::CreateCdm( void MediaInterfaceProxy::CreateCdm(
media::mojom::ContentDecryptionModuleRequest request) { media::mojom::ContentDecryptionModuleRequest request) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
GetMediaInterfaceFactory()->CreateCdm(std::move(request)); GetCdmInterfaceFactory()->CreateCdm(std::move(request));
} }
media::mojom::InterfaceFactory* media::mojom::InterfaceFactory*
...@@ -81,31 +80,52 @@ MediaInterfaceProxy::GetMediaInterfaceFactory() { ...@@ -81,31 +80,52 @@ MediaInterfaceProxy::GetMediaInterfaceFactory() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (!interface_factory_ptr_) if (!interface_factory_ptr_)
ConnectToService(); ConnectToMediaService();
DCHECK(interface_factory_ptr_); DCHECK(interface_factory_ptr_);
return interface_factory_ptr_.get(); 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__; DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
interface_factory_ptr_.reset(); interface_factory_ptr_.reset();
} }
void MediaInterfaceProxy::ConnectToService() { void MediaInterfaceProxy::OnCdmServiceConnectionError() {
DVLOG(1) << __FUNCTION__; DVLOG(1) << __FUNCTION__;
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!interface_factory_ptr_);
cdm_interface_factory_ptr_.reset();
}
service_manager::mojom::InterfaceProviderPtr
MediaInterfaceProxy::GetFrameServices() {
// Register frame services. // Register frame services.
service_manager::mojom::InterfaceProviderPtr interfaces; service_manager::mojom::InterfaceProviderPtr interfaces;
// TODO(xhwang): Replace this InterfaceProvider with a dedicated media host // TODO(xhwang): Replace this InterfaceProvider with a dedicated media host
// interface. See http://crbug.com/660573 // interface. See http://crbug.com/660573
auto provider = base::MakeUnique<media::MediaInterfaceProvider>( auto provider = base::MakeUnique<media::MediaInterfaceProvider>(
mojo::MakeRequest(&interfaces)); mojo::MakeRequest(&interfaces));
#if BUILDFLAG(ENABLE_MOJO_CDM) #if BUILDFLAG(ENABLE_MOJO_CDM)
// TODO(slan): Wrap these into a RenderFrame specific ProvisionFetcher impl. // TODO(slan): Wrap these into a RenderFrame specific ProvisionFetcher impl.
net::URLRequestContextGetter* context_getter = net::URLRequestContextGetter* context_getter =
...@@ -115,20 +135,49 @@ void MediaInterfaceProxy::ConnectToService() { ...@@ -115,20 +135,49 @@ void MediaInterfaceProxy::ConnectToService() {
provider->registry()->AddInterface(base::Bind( provider->registry()->AddInterface(base::Bind(
&ProvisionFetcherImpl::Create, base::RetainedRef(context_getter))); &ProvisionFetcherImpl::Create, base::RetainedRef(context_getter)));
#endif // BUILDFLAG(ENABLE_MOJO_CDM) #endif // BUILDFLAG(ENABLE_MOJO_CDM)
GetContentClient()->browser()->ExposeInterfacesToMediaService( GetContentClient()->browser()->ExposeInterfacesToMediaService(
provider->registry(), render_frame_host_); provider->registry(), render_frame_host_);
media_registries_.push_back(std::move(provider)); 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; media::mojom::MediaServicePtr media_service;
// TODO(slan): Use the BrowserContext Connector instead. See crbug.com/638950.
service_manager::Connector* connector = service_manager::Connector* connector =
ServiceManagerConnection::GetForProcess()->GetConnector(); ServiceManagerConnection::GetForProcess()->GetConnector();
connector->BindInterface(media::mojom::kMediaServiceName, &media_service); connector->BindInterface(media::mojom::kMediaServiceName, &media_service);
media_service->CreateInterfaceFactory(MakeRequest(&interface_factory_ptr_), media_service->CreateInterfaceFactory(MakeRequest(&interface_factory_ptr_),
std::move(interfaces)); GetFrameServices());
interface_factory_ptr_.set_connection_error_handler(base::Bind(
&MediaInterfaceProxy::OnConnectionError, base::Unretained(this))); 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 } // namespace content
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "media/mojo/features.h"
#include "media/mojo/interfaces/interface_factory.mojom.h" #include "media/mojo/interfaces/interface_factory.mojom.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
namespace media { namespace media {
class MediaInterfaceProvider; class MediaInterfaceProvider;
...@@ -27,8 +29,8 @@ class RenderFrameHost; ...@@ -27,8 +29,8 @@ class RenderFrameHost;
class MediaInterfaceProxy : public media::mojom::InterfaceFactory { class MediaInterfaceProxy : public media::mojom::InterfaceFactory {
public: public:
// Constructs MediaInterfaceProxy and bind |this| to the |request|. When // Constructs MediaInterfaceProxy and bind |this| to the |request|. When
// connection error happens on the client interface, |error_handler| should be // connection error happens on the client interface, |error_handler| will be
// fired. // called, which could destroy |this|.
MediaInterfaceProxy(RenderFrameHost* render_frame_host, MediaInterfaceProxy(RenderFrameHost* render_frame_host,
media::mojom::InterfaceFactoryRequest request, media::mojom::InterfaceFactoryRequest request,
const base::Closure& error_handler); const base::Closure& error_handler);
...@@ -42,12 +44,21 @@ class MediaInterfaceProxy : public media::mojom::InterfaceFactory { ...@@ -42,12 +44,21 @@ class MediaInterfaceProxy : public media::mojom::InterfaceFactory {
void CreateCdm(media::mojom::ContentDecryptionModuleRequest request) final; void CreateCdm(media::mojom::ContentDecryptionModuleRequest request) final;
private: private:
// Get the |interface_factory_ptr_|.
media::mojom::InterfaceFactory* GetMediaInterfaceFactory(); media::mojom::InterfaceFactory* GetMediaInterfaceFactory();
// Callback for connection error on |interface_factory_ptr_|. // Get the |cdm_interface_factory_ptr_|.
void OnConnectionError(); 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. // Safe to hold a raw pointer since |this| is owned by RenderFrameHostImpl.
RenderFrameHost* render_frame_host_; RenderFrameHost* render_frame_host_;
...@@ -58,9 +69,16 @@ class MediaInterfaceProxy : public media::mojom::InterfaceFactory { ...@@ -58,9 +69,16 @@ class MediaInterfaceProxy : public media::mojom::InterfaceFactory {
mojo::Binding<media::mojom::InterfaceFactory> binding_; 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_; 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_; base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(MediaInterfaceProxy); DISALLOW_COPY_AND_ASSIGN(MediaInterfaceProxy);
......
...@@ -357,11 +357,17 @@ ServiceManagerContext::ServiceManagerContext() { ...@@ -357,11 +357,17 @@ ServiceManagerContext::ServiceManagerContext() {
} }
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS) #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 // 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 // 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 // run it in the sandboxed utility process. See http://crbug.com/510604
out_of_process_services[media::mojom::kMediaServiceName] = { out_of_process_services[media::mojom::kCdmServiceName] = {
base::ASCIIToUTF16("Media Service"), SANDBOX_TYPE_NO_SANDBOX}; base::ASCIIToUTF16("Content Decryption Module Service"),
SANDBOX_TYPE_NO_SANDBOX};
#endif #endif
for (const auto& service : out_of_process_services) { for (const auto& service : out_of_process_services) {
......
...@@ -238,7 +238,8 @@ class ServiceManagerConnectionImpl::IOThreadContext ...@@ -238,7 +238,8 @@ class ServiceManagerConnectionImpl::IOThreadContext
const ServiceRequestHandler& handler) { const ServiceRequestHandler& handler) {
DCHECK(io_thread_checker_.CalledOnValidThread()); DCHECK(io_thread_checker_.CalledOnValidThread());
auto result = request_handlers_.insert(std::make_pair(name, handler)); 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") { ...@@ -182,6 +182,7 @@ service_manifest("packaged_services_manifest") {
source = "mojo/content_packaged_services_manifest.json" source = "mojo/content_packaged_services_manifest.json"
packaged_services = [ packaged_services = [
"//content/network:manifest", "//content/network:manifest",
"//media/mojo/services:cdm_manifest",
"//media/mojo/services:media_manifest", "//media/mojo/services:media_manifest",
"//services/data_decoder:manifest", "//services/data_decoder:manifest",
"//services/device:manifest", "//services/device:manifest",
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
}, },
"requires": { "requires": {
"*": [ "app" ], "*": [ "app" ],
"cdm": [ "media:cdm" ],
// In classic ash, the browser supplies ash interfaces to itself. // In classic ash, the browser supplies ash interfaces to itself.
"content_browser": [ "content_browser": [
"ash", "ash",
......
...@@ -47,7 +47,7 @@ namespace { ...@@ -47,7 +47,7 @@ namespace {
#if BUILDFLAG(ENABLE_PEPPER_CDMS) #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), ""); static_assert(BUILDFLAG(ENABLE_MOJO_CDM), "");
std::unique_ptr<media::CdmAllocator> CreateCdmAllocator() { std::unique_ptr<media::CdmAllocator> CreateCdmAllocator() {
...@@ -66,7 +66,7 @@ class CdmMojoMediaClient final : public media::MojoMediaClient { ...@@ -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>( return std::unique_ptr<service_manager::Service>(
new ::media::MediaService(base::MakeUnique<CdmMojoMediaClient>())); new ::media::MediaService(base::MakeUnique<CdmMojoMediaClient>()));
} }
...@@ -94,8 +94,8 @@ void UtilityServiceFactory::RegisterServices(ServiceMap* services) { ...@@ -94,8 +94,8 @@ void UtilityServiceFactory::RegisterServices(ServiceMap* services) {
#if BUILDFLAG(ENABLE_PEPPER_CDMS) #if BUILDFLAG(ENABLE_PEPPER_CDMS)
service_manager::EmbeddedServiceInfo info; service_manager::EmbeddedServiceInfo info;
info.factory = base::Bind(&CreateMediaService); info.factory = base::Bind(&CreateCdmService);
services->insert(std::make_pair(media::mojom::kMediaServiceName, info)); services->insert(std::make_pair(media::mojom::kCdmServiceName, info));
#endif #endif
service_manager::EmbeddedServiceInfo shape_detection_info; service_manager::EmbeddedServiceInfo shape_detection_info;
......
...@@ -149,6 +149,11 @@ declare_args() { ...@@ -149,6 +149,11 @@ declare_args() {
# - "utility": Use mojo media service hosted in the utility process. # - "utility": Use mojo media service hosted in the utility process.
mojo_media_host = "none" 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. # Default mojo_media_services and mojo_media_host on various platforms.
# Can be overridden by gn build arguments from the --args command line flag # Can be overridden by gn build arguments from the --args command line flag
# for local testing. # for local testing.
...@@ -167,10 +172,8 @@ declare_args() { ...@@ -167,10 +172,8 @@ declare_args() {
] ]
mojo_media_host = "gpu" mojo_media_host = "gpu"
} else if (enable_pepper_cdms) { } 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_services = [ "cdm" ]
mojo_media_host = "utility" enable_standalone_cdm_service = true
} }
} }
} }
......
...@@ -46,11 +46,16 @@ buildflag_header("features") { ...@@ -46,11 +46,16 @@ buildflag_header("features") {
enable_mojo_media_in_gpu_process = true enable_mojo_media_in_gpu_process = true
} else if (mojo_media_host == "utility") { } else if (mojo_media_host == "utility") {
enable_mojo_media_in_utility_process = true enable_mojo_media_in_utility_process = true
} else { } else if (!enable_standalone_cdm_service) {
assert(false, "Invalid mojo media host: $mojo_media_host") 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 = [ flags = [
"ENABLE_MOJO_MEDIA=$enable_mojo_media", "ENABLE_MOJO_MEDIA=$enable_mojo_media",
"ENABLE_TEST_MOJO_MEDIA_CLIENT=$enable_test_mojo_media_client", "ENABLE_TEST_MOJO_MEDIA_CLIENT=$enable_test_mojo_media_client",
...@@ -61,6 +66,7 @@ buildflag_header("features") { ...@@ -61,6 +66,7 @@ buildflag_header("features") {
"ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS=$enable_mojo_media_in_browser_process", "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_GPU_PROCESS=$enable_mojo_media_in_gpu_process",
"ENABLE_MOJO_MEDIA_IN_UTILITY_PROCESS=$enable_mojo_media_in_utility_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; ...@@ -8,3 +8,7 @@ module media.mojom;
// the |mojo_media_host| gn variable. This must match the name in // the |mojo_media_host| gn variable. This must match the name in
// media/mojo/services/media_manifest.json // media/mojo/services/media_manifest.json
const string kMediaServiceName = "media"; 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") { ...@@ -140,6 +140,11 @@ service_test("media_service_unittests") {
] ]
} }
service_manifest("cdm_manifest") {
name = "cdm"
source = "cdm_manifest.json"
}
service_manifest("media_manifest") { service_manifest("media_manifest") {
name = "media" name = "media"
source = "media_manifest.json" 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