From 3640f81f01fb7cce956e9fb92f0584eb17b34150 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Mon, 31 Aug 2015 13:28:07 +0200 Subject: [PATCH] Add Widevine CDM support (issue #1631) - Windows/Mac: Use `--enable-widevine-cdm` command-line flag to enable download of CDM binaries via the component updater. - Linux: Use `--widevide-cdm-path` and `--widevine-cdm-version` command-line flags to load CDM binaries that already exist on the system. - A cache-path value is usually required when CDM is enabled. --- cef.gyp | 18 + cef.gypi | 2 + libcef/browser/chrome_browser_process_stub.cc | 3 +- .../cef_component_updater_configurator.cc | 307 ++++++++++++++++++ .../cef_component_updater_configurator.h | 28 ++ libcef/browser/content_browser_client.cc | 4 + libcef/browser/context.cc | 41 +++ libcef/browser/context.h | 9 + .../extensions/plugin_info_message_filter.cc | 28 ++ .../extensions/plugin_info_message_filter.h | 5 + .../pepper/browser_pepper_host_factory.cc | 16 + ...per_isolated_file_system_message_filter.cc | 192 +++++++++++ ...pper_isolated_file_system_message_filter.h | 76 +++++ libcef/common/cef_messages.h | 14 + libcef/common/cef_switches.cc | 9 + libcef/common/cef_switches.h | 3 + libcef/common/content_client.cc | 71 ++++ libcef/common/main_delegate.cc | 15 + libcef/renderer/content_renderer_client.cc | 6 + libcef/renderer/content_renderer_client.h | 1 + libcef/renderer/media/cef_key_systems.cc | 141 ++++++++ libcef/renderer/media/cef_key_systems.h | 14 + tools/make_distrib.py | 1 + 23 files changed, 1002 insertions(+), 2 deletions(-) create mode 100644 libcef/browser/component_updater/cef_component_updater_configurator.cc create mode 100644 libcef/browser/component_updater/cef_component_updater_configurator.h create mode 100644 libcef/browser/pepper/pepper_isolated_file_system_message_filter.cc create mode 100644 libcef/browser/pepper/pepper_isolated_file_system_message_filter.h create mode 100644 libcef/renderer/media/cef_key_systems.cc create mode 100644 libcef/renderer/media/cef_key_systems.h diff --git a/cef.gyp b/cef.gyp index a882f451f..c0d33c518 100644 --- a/cef.gyp +++ b/cef.gyp @@ -936,6 +936,8 @@ # Generate chrome/common/safe_browsing/csd.pb.h required by # zip_analyzer_results.h via chrome_utility_messages.h '<(DEPTH)/chrome/chrome.gyp:safe_browsing_proto', + '<(DEPTH)/components/components.gyp:cdm_renderer', + '<(DEPTH)/components/components.gyp:component_updater', '<(DEPTH)/components/components.gyp:crash_component_breakpad_mac_to_be_deleted', '<(DEPTH)/components/components.gyp:crx_file', '<(DEPTH)/components/components.gyp:devtools_discovery', @@ -953,6 +955,7 @@ '<(DEPTH)/components/components.gyp:proxy_config', '<(DEPTH)/components/components.gyp:update_client', '<(DEPTH)/components/components.gyp:user_prefs', + '<(DEPTH)/components/components.gyp:version_info', '<(DEPTH)/components/components.gyp:web_cache_renderer', '<(DEPTH)/components/url_formatter/url_formatter.gyp:url_formatter', '<(DEPTH)/content/content.gyp:content_app_both', @@ -988,6 +991,8 @@ '<(DEPTH)/third_party/libxml/libxml.gyp:libxml', '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink', '<(DEPTH)/third_party/WebKit/Source/core/core.gyp:webcore', + '<(DEPTH)/third_party/widevine/cdm/widevine_cdm.gyp:widevinecdmadapter', + '<(DEPTH)/third_party/widevine/cdm/widevine_cdm.gyp:widevine_cdm_version_h', '<(DEPTH)/third_party/zlib/zlib.gyp:minizip', '<(DEPTH)/ui/gl/gl.gyp:gl', '<(DEPTH)/ui/base/ime/ui_base_ime.gyp:ui_base_ime', @@ -1047,6 +1052,8 @@ 'libcef/browser/download_item_impl.h', 'libcef/browser/download_manager_delegate.cc', 'libcef/browser/download_manager_delegate.h', + 'libcef/browser/component_updater/cef_component_updater_configurator.cc', + 'libcef/browser/component_updater/cef_component_updater_configurator.h', 'libcef/browser/extensions/api/streams_private/streams_private_api.cc', 'libcef/browser/extensions/api/streams_private/streams_private_api.h', 'libcef/browser/extensions/browser_context_keyed_service_factories.cc', @@ -1102,6 +1109,8 @@ 'libcef/browser/pepper/browser_pepper_host_factory.h', 'libcef/browser/pepper/pepper_flash_browser_host.cc', 'libcef/browser/pepper/pepper_flash_browser_host.h', + 'libcef/browser/pepper/pepper_isolated_file_system_message_filter.cc', + 'libcef/browser/pepper/pepper_isolated_file_system_message_filter.h', 'libcef/browser/pepper/device_id_fetcher.cc', 'libcef/browser/permission_manager.cc', 'libcef/browser/permission_manager.h', @@ -1246,6 +1255,8 @@ 'libcef/renderer/extensions/print_web_view_helper_delegate.h', 'libcef/renderer/frame_impl.cc', 'libcef/renderer/frame_impl.h', + 'libcef/renderer/media/cef_key_systems.cc', + 'libcef/renderer/media/cef_key_systems.h', 'libcef/renderer/pepper/pepper_helper.cc', 'libcef/renderer/pepper/pepper_helper.h', 'libcef/renderer/pepper/pepper_uma_host.cc', @@ -1386,6 +1397,12 @@ '<(DEPTH)/extensions/shell/browser/shell_display_info_provider.h', '<(DEPTH)/extensions/shell/browser/shell_web_contents_modal_dialog_manager.cc', '<(grit_out_dir)/grit/component_extension_resources_map.cc', + # Include sources for component-updater support. + '<(DEPTH)/chrome/browser/component_updater/widevine_cdm_component_installer.cc', + '<(DEPTH)/chrome/browser/component_updater/widevine_cdm_component_installer.h', + # Include sources for widevine support. + '<(DEPTH)/chrome/common/widevine_cdm_constants.cc', + '<(DEPTH)/chrome/common/widevine_cdm_constants.h', ], 'conditions': [ ['OS=="win"', { @@ -1497,6 +1514,7 @@ '<(PRODUCT_DIR)/icudtl.dat', '<(PRODUCT_DIR)/natives_blob.bin', '<(PRODUCT_DIR)/snapshot_blob.bin', + '<(PRODUCT_DIR)/widevinecdmadapter.plugin', 'libcef/resources/framework-Info.plist', ], 'mac_bundle_resources!': [ diff --git a/cef.gypi b/cef.gypi index df759bfc6..cde635189 100644 --- a/cef.gypi +++ b/cef.gypi @@ -9,6 +9,8 @@ # Set ENABLE_PRINTING=1 ENABLE_BASIC_PRINTING=1. 'enable_basic_printing': 1, 'enable_print_preview': 0, + # Enable support for Widevine CDM. + 'enable_widevine': 1, 'conditions': [ # Directory for CEF source files. [ 'OS=="win"', { diff --git a/libcef/browser/chrome_browser_process_stub.cc b/libcef/browser/chrome_browser_process_stub.cc index 166432024..91b3afff9 100644 --- a/libcef/browser/chrome_browser_process_stub.cc +++ b/libcef/browser/chrome_browser_process_stub.cc @@ -224,8 +224,7 @@ ChromeNetLog* ChromeBrowserProcessStub::net_log() { component_updater::ComponentUpdateService* ChromeBrowserProcessStub::component_updater() { - NOTIMPLEMENTED(); - return NULL; + return CefContext::Get()->component_updater(); } CRLSetFetcher* ChromeBrowserProcessStub::crl_set_fetcher() { diff --git a/libcef/browser/component_updater/cef_component_updater_configurator.cc b/libcef/browser/component_updater/cef_component_updater_configurator.cc new file mode 100644 index 000000000..7763d6eb6 --- /dev/null +++ b/libcef/browser/component_updater/cef_component_updater_configurator.cc @@ -0,0 +1,307 @@ +// Copyright 2014 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 "libcef/browser/component_updater/cef_component_updater_configurator.h" +#include "include/cef_version.h" + +#include +#include +#include + +#include "base/command_line.h" +#include "base/compiler_specific.h" +#include "base/strings/stringprintf.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/version.h" +#include "build/build_config.h" +#include "chrome/browser/update_client/chrome_update_query_params_delegate.h" +#include "components/update_client/component_patcher_operation.h" +#include "components/component_updater/component_updater_switches.h" +#include "components/component_updater/component_updater_url_constants.h" +#include "components/update_client/configurator.h" +#include "content/public/browser/browser_thread.h" +#include "net/url_request/url_request_context_getter.h" +#include "url/gurl.h" + +#if defined(OS_WIN) +#include "base/win/win_util.h" +#endif // OS_WIN + +using update_client::Configurator; + +namespace component_updater { + +namespace { + +// Default time constants. +const int kDelayOneMinute = 60; +const int kDelayOneHour = kDelayOneMinute * 60; + +// Debug values you can pass to --component-updater=value1,value2. +// Speed up component checking. +const char kSwitchFastUpdate[] = "fast-update"; + +// Add "testrequest=1" attribute to the update check request. +const char kSwitchRequestParam[] = "test-request"; + +// Disables pings. Pings are the requests sent to the update server that report +// the success or the failure of component install or update attempts. +extern const char kSwitchDisablePings[] = "disable-pings"; + +// Sets the URL for updates. +const char kSwitchUrlSource[] = "url-source"; + +// Disables differential updates. +const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates"; + +#if defined(OS_WIN) +// Disables background downloads. +const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads"; +#endif // defined(OS_WIN) + +// Returns true if and only if |test| is contained in |vec|. +bool HasSwitchValue(const std::vector& vec, const char* test) { + if (vec.empty()) + return 0; + return (std::find(vec.begin(), vec.end(), test) != vec.end()); +} + +// Returns true if falling back on an alternate, unsafe, service URL is +// allowed. In the fallback case, the security of the component update relies +// only on the integrity of the CRX payloads, which is self-validating. +// This is allowed only for some of the pre-Windows Vista versions not including +// Windows XP SP3. As a side note, pings could be sent to the alternate URL too. +bool CanUseAltUrlSource() { +#if defined(OS_WIN) + return !base::win::MaybeHasSHA256Support(); +#else + return false; +#endif // OS_WIN +} + +// If there is an element of |vec| of the form |test|=.*, returns the right- +// hand side of that assignment. Otherwise, returns an empty string. +// The right-hand side may contain additional '=' characters, allowing for +// further nesting of switch arguments. +std::string GetSwitchArgument(const std::vector& vec, + const char* test) { + if (vec.empty()) + return std::string(); + for (std::vector::const_iterator it = vec.begin(); + it != vec.end(); + ++it) { + const std::size_t found = it->find("="); + if (found != std::string::npos) { + if (it->substr(0, found) == test) { + return it->substr(found + 1); + } + } + } + return std::string(); +} + +class CefConfigurator : public Configurator { + public: + CefConfigurator(const base::CommandLine* cmdline, + net::URLRequestContextGetter* url_request_getter); + + int InitialDelay() const override; + int NextCheckDelay() const override; + int StepDelay() const override; + int OnDemandDelay() const override; + int UpdateDelay() const override; + std::vector UpdateUrl() const override; + std::vector PingUrl() const override; + base::Version GetBrowserVersion() const override; + std::string GetChannel() const override; + std::string GetLang() const override; + std::string GetOSLongName() const override; + std::string ExtraRequestParams() const override; + net::URLRequestContextGetter* RequestContext() const override; + scoped_refptr + CreateOutOfProcessPatcher() const override; + bool DeltasEnabled() const override; + bool UseBackgroundDownloader() const override; + scoped_refptr GetSequencedTaskRunner() + const override; + scoped_refptr GetSingleThreadTaskRunner() + const override; + + private: + friend class base::RefCountedThreadSafe; + + ~CefConfigurator() override {} + + net::URLRequestContextGetter* url_request_getter_; + std::string extra_info_; + GURL url_source_override_; + bool fast_update_; + bool pings_enabled_; + bool deltas_enabled_; + bool background_downloads_enabled_; + bool fallback_to_alt_source_url_enabled_; +}; + +CefConfigurator::CefConfigurator( + const base::CommandLine* cmdline, + net::URLRequestContextGetter* url_request_getter) + : url_request_getter_(url_request_getter), + fast_update_(false), + pings_enabled_(false), + deltas_enabled_(false), + background_downloads_enabled_(false), + fallback_to_alt_source_url_enabled_(false) { + // Parse comma-delimited debug flags. + std::vector switch_values = base::SplitString( + cmdline->GetSwitchValueASCII(switches::kComponentUpdater), + ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + fast_update_ = HasSwitchValue(switch_values, kSwitchFastUpdate); + pings_enabled_ = !HasSwitchValue(switch_values, kSwitchDisablePings); + deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates); + + // TODO(dberger): Pull this (and possibly the various hard-coded + // delay params in this file) from cef settings. + fast_update_ = true; + +#if defined(OS_WIN) + background_downloads_enabled_ = + !HasSwitchValue(switch_values, kSwitchDisableBackgroundDownloads); +#else + background_downloads_enabled_ = false; +#endif + + const std::string switch_url_source = + GetSwitchArgument(switch_values, kSwitchUrlSource); + if (!switch_url_source.empty()) { + url_source_override_ = GURL(switch_url_source); + DCHECK(url_source_override_.is_valid()); + } + + if (HasSwitchValue(switch_values, kSwitchRequestParam)) + extra_info_ += "testrequest=\"1\""; + + fallback_to_alt_source_url_enabled_ = CanUseAltUrlSource(); +} + +int CefConfigurator::InitialDelay() const { + return fast_update_ ? 10 : (6 * kDelayOneMinute); +} + +int CefConfigurator::NextCheckDelay() const { + return fast_update_ ? 60 : (6 * kDelayOneHour); +} + +int CefConfigurator::StepDelay() const { + return fast_update_ ? 1 : 1; +} + +int CefConfigurator::OnDemandDelay() const { + return fast_update_ ? 2 : (30 * kDelayOneMinute); +} + +int CefConfigurator::UpdateDelay() const { + return fast_update_ ? 10 : (15 * kDelayOneMinute); +} + +std::vector CefConfigurator::UpdateUrl() const { + std::vector urls; + if (url_source_override_.is_valid()) { + urls.push_back(GURL(url_source_override_)); + } else { + urls.push_back(GURL(kUpdaterDefaultUrl)); + if (fallback_to_alt_source_url_enabled_) { + urls.push_back(GURL(kUpdaterAltUrl)); + } + } + return urls; +} + +std::vector CefConfigurator::PingUrl() const { + return pings_enabled_ ? UpdateUrl() : std::vector(); +} + +base::Version CefConfigurator::GetBrowserVersion() const { + return base::Version(base::StringPrintf("%d.%d.%d.%d", + CHROME_VERSION_MAJOR, + CHROME_VERSION_MINOR, + CHROME_VERSION_BUILD, + CHROME_VERSION_PATCH)); +} + +std::string CefConfigurator::GetChannel() const { + return ""; +} + +std::string CefConfigurator::GetLang() const { + return ""; +} + +std::string CefConfigurator::GetOSLongName() const { +#if defined(OS_WIN) + return "Windows"; +#elif defined(OS_MACOSX) + return "Mac OS X"; +#elif defined(OS_CHROMEOS) + return "Chromium OS"; +#elif defined(OS_ANDROID) + return "Android"; +#elif defined(OS_LINUX) + return "Linux"; +#elif defined(OS_FREEBSD) + return "FreeBSD"; +#elif defined(OS_OPENBSD) + return "OpenBSD"; +#elif defined(OS_SOLARIS) + return "Solaris"; +#else + return "Unknown"; +#endif +} + +std::string CefConfigurator::ExtraRequestParams() const { + return extra_info_; +} + +net::URLRequestContextGetter* CefConfigurator::RequestContext() const { + return url_request_getter_; +} + +scoped_refptr +CefConfigurator::CreateOutOfProcessPatcher() const { + return NULL; +} + +bool CefConfigurator::DeltasEnabled() const { + return deltas_enabled_; +} + +bool CefConfigurator::UseBackgroundDownloader() const { + return background_downloads_enabled_; +} + +scoped_refptr +CefConfigurator::GetSequencedTaskRunner() const { + return content::BrowserThread::GetBlockingPool() + ->GetSequencedTaskRunnerWithShutdownBehavior( + content::BrowserThread::GetBlockingPool()->GetSequenceToken(), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); +} + +scoped_refptr +CefConfigurator::GetSingleThreadTaskRunner() const { + return content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::FILE); +} + +} // namespace + +scoped_refptr +MakeCefComponentUpdaterConfigurator( + const base::CommandLine* cmdline, + net::URLRequestContextGetter* context_getter) { + return new CefConfigurator(cmdline, context_getter); +} + +} // namespace component_updater diff --git a/libcef/browser/component_updater/cef_component_updater_configurator.h b/libcef/browser/component_updater/cef_component_updater_configurator.h new file mode 100644 index 000000000..400d45aaa --- /dev/null +++ b/libcef/browser/component_updater/cef_component_updater_configurator.h @@ -0,0 +1,28 @@ +// Copyright 2014 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 LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_ +#define LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_ + +#include "base/memory/ref_counted.h" +#include "components/update_client/configurator.h" + +namespace base { +class CommandLine; +} + +namespace net { +class URLRequestContextGetter; +} + +namespace component_updater { + +scoped_refptr +MakeCefComponentUpdaterConfigurator( + const base::CommandLine* cmdline, + net::URLRequestContextGetter* context_getter); + +} // namespace component_updater + +#endif // LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_ diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index 42a549d16..205a789e2 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -722,6 +722,8 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches( switches::kPpapiFlashPath, switches::kPpapiFlashVersion, switches::kUncaughtExceptionStackSize, + switches::kWidevineCdmPath, + switches::kWidevineCdmVersion, }; command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, arraysize(kSwitchNames)); @@ -734,6 +736,8 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches( static const char* const kSwitchNames[] = { switches::kPpapiFlashPath, switches::kPpapiFlashVersion, + switches::kWidevineCdmPath, + switches::kWidevineCdmVersion, }; command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, arraysize(kSwitchNames)); diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index 7936d397b..263a9d1c9 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -9,6 +9,7 @@ #include "libcef/browser/browser_main.h" #include "libcef/browser/browser_message_loop.h" #include "libcef/browser/chrome_browser_process_stub.h" +#include "libcef/browser/component_updater/cef_component_updater_configurator.h" #include "libcef/browser/content_browser_client.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/trace_subscriber.h" @@ -22,7 +23,11 @@ #include "base/debug/debugger.h" #include "base/files/file_util.h" #include "base/synchronization/waitable_event.h" +#include "base/threading/thread_restrictions.h" +#include "chrome/browser/component_updater/widevine_cdm_component_installer.h" #include "chrome/browser/printing/print_job_manager.h" +#include "components/component_updater/component_updater_service.h" +#include "components/update_client/configurator.h" #include "content/public/app/content_main.h" #include "content/public/app/content_main_runner.h" #include "content/public/browser/notification_service.h" @@ -330,6 +335,23 @@ CefTraceSubscriber* CefContext::GetTraceSubscriber() { return trace_subscriber_.get(); } +component_updater::ComponentUpdateService* +CefContext::component_updater() { + if (!component_updater_.get()) { + CEF_REQUIRE_UIT_RETURN(NULL); + scoped_refptr configurator = + component_updater::MakeCefComponentUpdaterConfigurator( + base::CommandLine::ForCurrentProcess(), + CefContentBrowserClient::Get()->browser_context()-> + request_context().get()); + // Creating the component updater does not do anything, components + // need to be registered and Start() needs to be called. + component_updater_.reset(component_updater::ComponentUpdateServiceFactory( + configurator).release()); + } + return component_updater_.get(); +} + void CefContext::PopulateRequestContextSettings( CefRequestContextSettings* settings) { CefRefPtr command_line = @@ -345,12 +367,31 @@ void CefContext::PopulateRequestContextSettings( CefString(&settings_.accept_language_list); } +void RegisterComponentsForUpdate() { + component_updater::ComponentUpdateService* cus = + CefContext::Get()->component_updater(); + + // Registration can be before or after cus->Start() so it is ok to post + // a task to the UI thread to do registration once you done the necessary + // file IO to know you existing component version. +#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableWidevineCdm)) { + RegisterWidevineCdmComponent(cus); + } +#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) +} + void CefContext::OnContextInitialized() { CEF_REQUIRE_UIT(); // Must be created after the NotificationService. print_job_manager_.reset(new printing::PrintJobManager()); + bool io_was_allowed = base::ThreadRestrictions::SetIOAllowed(true); + RegisterComponentsForUpdate(); + base::ThreadRestrictions::SetIOAllowed(io_was_allowed); + // Notify the handler. CefRefPtr app = CefContentClient::Get()->application(); if (app.get()) { diff --git a/libcef/browser/context.h b/libcef/browser/context.h index eaab1129e..4f57c5e12 100644 --- a/libcef/browser/context.h +++ b/libcef/browser/context.h @@ -19,6 +19,10 @@ namespace base { class WaitableEvent; } +namespace component_updater { +class ComponentUpdateService; +} + namespace content { class ContentMainRunner; } @@ -63,6 +67,8 @@ class CefContext { return print_job_manager_.get(); } + component_updater::ComponentUpdateService* component_updater(); + CefTraceSubscriber* GetTraceSubscriber(); // Populate the request context settings based on CefSettings and command- @@ -94,6 +100,9 @@ class CefContext { // Only accessed on the UI Thread. scoped_ptr print_job_manager_; + + // Initially only for Widevine components. + scoped_ptr component_updater_; }; // Helper macro that returns true if the global context is in a valid state. diff --git a/libcef/browser/extensions/plugin_info_message_filter.cc b/libcef/browser/extensions/plugin_info_message_filter.cc index 2623190bb..12c872e21 100644 --- a/libcef/browser/extensions/plugin_info_message_filter.cc +++ b/libcef/browser/extensions/plugin_info_message_filter.cc @@ -67,6 +67,8 @@ bool CefPluginInfoMessageFilter::OnMessageReceived(const IPC::Message& message) IPC_BEGIN_MESSAGE_MAP(CefPluginInfoMessageFilter, message) IPC_MESSAGE_HANDLER_DELAY_REPLY(CefViewHostMsg_GetPluginInfo, OnGetPluginInfo) + IPC_MESSAGE_HANDLER(CefViewHostMsg_IsInternalPluginAvailableForMimeType, + OnIsInternalPluginAvailableForMimeType) IPC_MESSAGE_UNHANDLED(return false) IPC_END_MESSAGE_MAP() return true; @@ -214,4 +216,30 @@ bool CefPluginInfoMessageFilter::Context::FindEnabledPlugin( return enabled; } +void CefPluginInfoMessageFilter::OnIsInternalPluginAvailableForMimeType( + const std::string& mime_type, + bool* is_available, + std::vector* additional_param_names, + std::vector* additional_param_values) { + std::vector plugins; + PluginService::GetInstance()->GetInternalPlugins(&plugins); + + for (size_t i = 0; i < plugins.size(); ++i) { + const WebPluginInfo& plugin = plugins[i]; + const std::vector& mime_types = + plugin.mime_types; + for (size_t j = 0; j < mime_types.size(); ++j) { + if (mime_types[j].mime_type == mime_type) { + // TODO(cef): Maybe allow plugins to be disabled here. + *is_available = true; + *additional_param_names = mime_types[j].additional_param_names; + *additional_param_values = mime_types[j].additional_param_values; + return; + } + } + } + + *is_available = false; +} + } // namespace extensions diff --git a/libcef/browser/extensions/plugin_info_message_filter.h b/libcef/browser/extensions/plugin_info_message_filter.h index 5abc415f1..a67c278a9 100644 --- a/libcef/browser/extensions/plugin_info_message_filter.h +++ b/libcef/browser/extensions/plugin_info_message_filter.h @@ -76,6 +76,11 @@ class CefPluginInfoMessageFilter : public content::BrowserMessageFilter { const GURL& top_origin_url, const std::string& mime_type, IPC::Message* reply_msg); + void OnIsInternalPluginAvailableForMimeType( + const std::string& mime_type, + bool* is_available, + std::vector* additional_param_names, + std::vector* additional_param_values); // |params| wraps the parameters passed to |OnGetPluginInfo|, because // |base::Bind| doesn't support the required arity . diff --git a/libcef/browser/pepper/browser_pepper_host_factory.cc b/libcef/browser/pepper/browser_pepper_host_factory.cc index cffc84b23..e40a01c59 100644 --- a/libcef/browser/pepper/browser_pepper_host_factory.cc +++ b/libcef/browser/pepper/browser_pepper_host_factory.cc @@ -5,6 +5,7 @@ #include "libcef/browser/pepper/browser_pepper_host_factory.h" #include "libcef/browser/pepper/pepper_flash_browser_host.h" +#include "libcef/browser/pepper/pepper_isolated_file_system_message_filter.h" #include "build/build_config.h" #include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" @@ -56,6 +57,21 @@ scoped_ptr CefBrowserPepperHostFactory::CreateResourceHost( } } + // Permissions for the following interfaces will be checked at the + // time of the corresponding instance's methods calls (because + // permission check can be performed only on the UI + // thread). Currently these interfaces are available only for + // whitelisted apps which may not have access to the other private + // interfaces. + if (message.type() == PpapiHostMsg_IsolatedFileSystem_Create::ID) { + PepperIsolatedFileSystemMessageFilter* isolated_fs_filter = + PepperIsolatedFileSystemMessageFilter::Create(instance, host_); + if (!isolated_fs_filter) + return scoped_ptr(); + return scoped_ptr( + new MessageFilterHost(host, instance, resource, isolated_fs_filter)); + } + NOTREACHED() << "Unhandled message type: " << message.type(); return scoped_ptr(); } diff --git a/libcef/browser/pepper/pepper_isolated_file_system_message_filter.cc b/libcef/browser/pepper/pepper_isolated_file_system_message_filter.cc new file mode 100644 index 000000000..41b057a37 --- /dev/null +++ b/libcef/browser/pepper/pepper_isolated_file_system_message_filter.cc @@ -0,0 +1,192 @@ +// Copyright 2013 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 "libcef/browser/pepper/pepper_isolated_file_system_message_filter.h" + +#include "libcef/browser/browser_context_impl.h" + +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pepper_permission_util.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/render_view_host.h" +#if defined(ENABLE_EXTENSIONS) +#include "extensions/browser/extension_registry.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_set.h" +#endif +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/file_system_util.h" +#include "storage/browser/fileapi/isolated_context.h" + +namespace { + +const char* kPredefinedAllowedCrxFsOrigins[] = { + "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F", // see crbug.com/234789 + "4EB74897CB187C7633357C2FE832E0AD6A44883A" // see crbug.com/234789 +}; + +} // namespace + +// static +PepperIsolatedFileSystemMessageFilter* +PepperIsolatedFileSystemMessageFilter::Create(PP_Instance instance, + content::BrowserPpapiHost* host) { + int render_process_id; + int unused_render_frame_id; + if (!host->GetRenderFrameIDsForInstance( + instance, &render_process_id, &unused_render_frame_id)) { + return NULL; + } + return new PepperIsolatedFileSystemMessageFilter( + render_process_id, + host->GetProfileDataDirectory(), + host->GetDocumentURLForInstance(instance), + host->GetPpapiHost()); +} + +PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter( + int render_process_id, + const base::FilePath& profile_directory, + const GURL& document_url, + ppapi::host::PpapiHost* ppapi_host) + : render_process_id_(render_process_id), + profile_directory_(profile_directory), + document_url_(document_url), + ppapi_host_(ppapi_host) { + for (size_t i = 0; i < arraysize(kPredefinedAllowedCrxFsOrigins); ++i) + allowed_crxfs_origins_.insert(kPredefinedAllowedCrxFsOrigins[i]); +} + +PepperIsolatedFileSystemMessageFilter:: + ~PepperIsolatedFileSystemMessageFilter() {} + +scoped_refptr +PepperIsolatedFileSystemMessageFilter::OverrideTaskRunnerForMessage( + const IPC::Message& msg) { + // In order to reach ExtensionSystem, we need to get ProfileManager first. + // ProfileManager lives in UI thread, so we need to do this in UI thread. + return content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::UI); +} + +int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + PPAPI_BEGIN_MESSAGE_MAP(PepperIsolatedFileSystemMessageFilter, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_IsolatedFileSystem_BrowserOpen, + OnOpenFileSystem) + PPAPI_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +std::string PepperIsolatedFileSystemMessageFilter::CreateCrxFileSystem( + content::BrowserContext* profile) { +#if defined(ENABLE_EXTENSIONS) + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID( + document_url_.host()); + if (!extension) + return std::string(); + + // First level directory for isolated filesystem to lookup. + std::string kFirstLevelDirectory("crxfs"); + return storage::IsolatedContext::GetInstance()->RegisterFileSystemForPath( + storage::kFileSystemTypeNativeLocal, + std::string(), + extension->path(), + &kFirstLevelDirectory); +#else + return std::string(); +#endif +} + +int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( + ppapi::host::HostMessageContext* context, + PP_IsolatedFileSystemType_Private type) { + switch (type) { + case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_INVALID: + break; + case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX: + return OpenCrxFileSystem(context); + case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE: + return OpenPluginPrivateFileSystem(context); + } + NOTREACHED(); + context->reply_msg = + PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string()); + return PP_ERROR_FAILED; +} + +int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem( + ppapi::host::HostMessageContext* context) { +#if defined(ENABLE_EXTENSIONS) + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + scoped_refptr browser_context = + CefBrowserContextImpl::GetForCachePath(profile_directory_); + DCHECK(browser_context); + + const extensions::ExtensionSet* extension_set = NULL; + if (browser_context) { + extension_set = &extensions::ExtensionRegistry::Get(browser_context.get())-> + enabled_extensions(); + } + if (!chrome::IsExtensionOrSharedModuleWhitelisted( + document_url_, extension_set, allowed_crxfs_origins_) && + !chrome::IsHostAllowedByCommandLine( + document_url_, extension_set, switches::kAllowNaClCrxFsAPI)) { + LOG(ERROR) << "Host " << document_url_.host() << " cannot use CrxFs API."; + return PP_ERROR_NOACCESS; + } + + // TODO(raymes): When we remove FileSystem from the renderer, we should create + // a pending PepperFileSystemBrowserHost here with the fsid and send the + // pending host ID back to the plugin. + const std::string fsid = CreateCrxFileSystem(browser_context.get()); + if (fsid.empty()) { + context->reply_msg = + PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string()); + return PP_ERROR_NOTSUPPORTED; + } + + // Grant readonly access of isolated filesystem to renderer process. + content::ChildProcessSecurityPolicy* policy = + content::ChildProcessSecurityPolicy::GetInstance(); + policy->GrantReadFileSystem(render_process_id_, fsid); + + context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid); + return PP_OK; +#else + return PP_ERROR_NOTSUPPORTED; +#endif +} + +int32_t PepperIsolatedFileSystemMessageFilter::OpenPluginPrivateFileSystem( + ppapi::host::HostMessageContext* context) { + DCHECK(ppapi_host_); + // Only plugins with private permission can open the filesystem. + if (!ppapi_host_->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) + return PP_ERROR_NOACCESS; + + const std::string& root_name = ppapi::IsolatedFileSystemTypeToRootName( + PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); + const std::string& fsid = + storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath( + storage::kFileSystemTypePluginPrivate, root_name, base::FilePath()); + + // Grant full access of isolated filesystem to renderer process. + content::ChildProcessSecurityPolicy* policy = + content::ChildProcessSecurityPolicy::GetInstance(); + policy->GrantCreateReadWriteFileSystem(render_process_id_, fsid); + + context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid); + return PP_OK; +} diff --git a/libcef/browser/pepper/pepper_isolated_file_system_message_filter.h b/libcef/browser/pepper/pepper_isolated_file_system_message_filter.h new file mode 100644 index 000000000..37cbfe96f --- /dev/null +++ b/libcef/browser/pepper/pepper_isolated_file_system_message_filter.h @@ -0,0 +1,76 @@ +// Copyright 2013 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 CEF_LIBCEF_BROWSER_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ +#define CEF_LIBCEF_BROWSER_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ + +#include +#include + +#include "base/files/file_path.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/private/ppb_isolated_file_system_private.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/host/resource_message_filter.h" +#include "url/gurl.h" + +namespace content { +class BrowserContext; +class BrowserPpapiHost; +} + +namespace ppapi { +namespace host { +struct HostMessageContext; +} // namespace host +} // namespace ppapi + +class PepperIsolatedFileSystemMessageFilter + : public ppapi::host::ResourceMessageFilter { + public: + static PepperIsolatedFileSystemMessageFilter* Create( + PP_Instance instance, + content::BrowserPpapiHost* host); + + // ppapi::host::ResourceMessageFilter implementation. + scoped_refptr OverrideTaskRunnerForMessage( + const IPC::Message& msg) override; + int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) override; + + private: + PepperIsolatedFileSystemMessageFilter(int render_process_id, + const base::FilePath& profile_directory, + const GURL& document_url, + ppapi::host::PpapiHost* ppapi_host_); + + ~PepperIsolatedFileSystemMessageFilter() override; + + // Returns filesystem id of isolated filesystem if valid, or empty string + // otherwise. This must run on the UI thread because ProfileManager only + // allows access on that thread. + std::string CreateCrxFileSystem(content::BrowserContext* profile); + + int32_t OnOpenFileSystem(ppapi::host::HostMessageContext* context, + PP_IsolatedFileSystemType_Private type); + int32_t OpenCrxFileSystem(ppapi::host::HostMessageContext* context); + int32_t OpenPluginPrivateFileSystem(ppapi::host::HostMessageContext* context); + + const int render_process_id_; + // Keep a copy from original thread. + const base::FilePath profile_directory_; + const GURL document_url_; + + // Not owned by this object. + ppapi::host::PpapiHost* ppapi_host_; + + // Set of origins that can use CrxFs private APIs from NaCl. + std::set allowed_crxfs_origins_; + + DISALLOW_COPY_AND_ASSIGN(PepperIsolatedFileSystemMessageFilter); +}; + +#endif // CEF_LIBCEF_BROWSER_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ diff --git a/libcef/common/cef_messages.h b/libcef/common/cef_messages.h index fb9122971..b88173708 100644 --- a/libcef/common/cef_messages.h +++ b/libcef/common/cef_messages.h @@ -230,6 +230,20 @@ IPC_SYNC_MESSAGE_CONTROL4_1(CefViewHostMsg_GetPluginInfo, std::string /* mime_type */, CefViewHostMsg_GetPluginInfo_Output /* output */) +// Returns whether any internal plugin supporting |mime_type| is registered and +// enabled. Does not determine whether the plugin can actually be instantiated +// (e.g. whether it has all its dependencies). +// When the returned *|is_available| is true, |additional_param_names| and +// |additional_param_values| contain the name-value pairs, if any, specified +// for the *first* non-disabled plugin found that is registered for |mime_type|. +// Based on ChromeViewHostMsg_IsInternalPluginAvailableForMimeType. +IPC_SYNC_MESSAGE_CONTROL1_3( + CefViewHostMsg_IsInternalPluginAvailableForMimeType, + std::string /* mime_type */, + bool /* is_available */, + std::vector /* additional_param_names */, + std::vector /* additional_param_values */) + // Sent when a frame is identified for the first time. IPC_MESSAGE_ROUTED3(CefHostMsg_FrameIdentified, int64 /* frame_id */, diff --git a/libcef/common/cef_switches.cc b/libcef/common/cef_switches.cc index 60b0e5eaf..c20841f2a 100644 --- a/libcef/common/cef_switches.cc +++ b/libcef/common/cef_switches.cc @@ -107,4 +107,13 @@ const char kDisablePdfExtension[] = "disable-pdf-extension"; // upcoming version of Chromium. const char kEnableNPAPI[] = "enable-npapi"; +// Enable Widevine CDM. +const char kEnableWidevineCdm[] = "enable-widevine-cdm"; + +// Path to Widevine CDM binaries. +const char kWidevineCdmPath[] = "widevine-cdm-path"; + +// Widevine CDM version. +const char kWidevineCdmVersion[] = "widevine-cdm-version"; + } // namespace switches diff --git a/libcef/common/cef_switches.h b/libcef/common/cef_switches.h index 592fe2d74..0281167aa 100644 --- a/libcef/common/cef_switches.h +++ b/libcef/common/cef_switches.h @@ -45,6 +45,9 @@ extern const char kEnableSystemFlash[]; extern const char kDisableScrollBounce[]; extern const char kDisablePdfExtension[]; extern const char kEnableNPAPI[]; +extern const char kEnableWidevineCdm[]; +extern const char kWidevineCdmPath[]; +extern const char kWidevineCdmVersion[]; } // namespace switches diff --git a/libcef/common/content_client.cc b/libcef/common/content_client.cc index a423159d5..798ddf1c3 100644 --- a/libcef/common/content_client.cc +++ b/libcef/common/content_client.cc @@ -34,6 +34,14 @@ #include "ppapi/shared_impl/ppapi_permissions.h" #include "ui/base/resource/resource_bundle.h" +#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. + +// The following must be after widevine_cdm_version.h. +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \ + !defined(WIDEVINE_CDM_IS_COMPONENT) +#include "chrome/common/widevine_cdm_constants.h" +#endif + namespace { CefContentClient* g_content_client = NULL; @@ -171,6 +179,68 @@ bool GetSystemPepperFlash(content::PepperPluginInfo* plugin) { return true; } +void AddWidevineCdmFromCommandLine( + std::vector* plugins) { +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \ + !defined(WIDEVINE_CDM_IS_COMPONENT) + static bool skip_widevine_cdm_file_check = false; + + base::FilePath widevine_cdm_path = + base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( + switches::kWidevineCdmPath); + if (!widevine_cdm_path.empty()) { + widevine_cdm_path = + widevine_cdm_path.AppendASCII(kWidevineCdmAdapterFileName); + } + + // Also get the version from the command-line. Should be something like + // 1.4.8.824. + const std::string& widevine_cdm_version = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kWidevineCdmVersion); + + if (!widevine_cdm_path.empty() && !widevine_cdm_version.empty()) { + if (skip_widevine_cdm_file_check || base::PathExists(widevine_cdm_path)) { + content::PepperPluginInfo widevine_cdm; + widevine_cdm.is_out_of_process = true; + widevine_cdm.path = widevine_cdm_path; + widevine_cdm.name = kWidevineCdmDisplayName; + widevine_cdm.description = kWidevineCdmDescription + + std::string(" (version: ") + + widevine_cdm_version + ")"; + widevine_cdm.version = widevine_cdm_version; + content::WebPluginMimeType widevine_cdm_mime_type( + kWidevineCdmPluginMimeType, + kWidevineCdmPluginExtension, + kWidevineCdmPluginMimeTypeDescription); + + // Add the supported codecs as if they came from the component manifest. + std::vector codecs; + codecs.push_back(kCdmSupportedCodecVorbis); + codecs.push_back(kCdmSupportedCodecVp8); + codecs.push_back(kCdmSupportedCodecVp9); +#if defined(USE_PROPRIETARY_CODECS) + codecs.push_back(kCdmSupportedCodecAac); + codecs.push_back(kCdmSupportedCodecAvc1); +#endif // defined(USE_PROPRIETARY_CODECS) + std::string codec_string = base::JoinString( + codecs, std::string(1, kCdmSupportedCodecsValueDelimiter)); + widevine_cdm_mime_type.additional_param_names.push_back( + base::ASCIIToUTF16(kCdmSupportedCodecsParamName)); + widevine_cdm_mime_type.additional_param_values.push_back( + base::ASCIIToUTF16(codec_string)); + + widevine_cdm.mime_types.push_back(widevine_cdm_mime_type); + widevine_cdm.permissions = kWidevineCdmPluginPermissions; + plugins->push_back(widevine_cdm); + + skip_widevine_cdm_file_check = true; + } + } +#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && + // !defined(WIDEVINE_CDM_IS_COMPONENT) +} + } // namespace const char CefContentClient::kPDFPluginPath[] = "internal-pdf-viewer"; @@ -197,6 +267,7 @@ void CefContentClient::AddPepperPlugins( std::vector* plugins) { ComputeBuiltInPlugins(plugins); AddPepperFlashFromCommandLine(plugins); + AddWidevineCdmFromCommandLine(plugins); content::PepperPluginInfo plugin; if (GetSystemPepperFlash(&plugin)) diff --git a/libcef/common/main_delegate.cc b/libcef/common/main_delegate.cc index 02a0829d1..19c2c9083 100644 --- a/libcef/common/main_delegate.cc +++ b/libcef/common/main_delegate.cc @@ -26,6 +26,7 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/widevine_cdm_constants.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/browser/render_process_host.h" #include "content/public/common/content_switches.h" @@ -36,6 +37,8 @@ #include "ui/base/ui_base_paths.h" #include "ui/base/ui_base_switches.h" +#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. + #include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. #if defined(IPC_MESSAGE_LOG_ENABLED) @@ -525,6 +528,18 @@ void CefMainDelegate::PreSandboxStartup() { user_data_path.AppendASCII("Dictionaries"), false, // May not be an absolute path. true); // Create if necessary. + +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + const base::FilePath& widevine_plugin_path = GetResourcesFilePath(); + PathService::Override(chrome::FILE_WIDEVINE_CDM_ADAPTER, + widevine_plugin_path.AppendASCII( + kWidevineCdmAdapterFileName)); +#if defined(WIDEVINE_CDM_IS_COMPONENT) + PathService::Override(chrome::DIR_COMPONENT_WIDEVINE_CDM, + user_data_path.Append(kWidevineCdmBaseDirectory)); +#endif // defined(WIDEVINE_CDM_IS_COMPONENT) +#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + } if (command_line->HasSwitch(switches::kDisablePackLoading)) diff --git a/libcef/renderer/content_renderer_client.cc b/libcef/renderer/content_renderer_client.cc index 2b3392270..c97b2a52a 100644 --- a/libcef/renderer/content_renderer_client.cc +++ b/libcef/renderer/content_renderer_client.cc @@ -17,6 +17,7 @@ #include "libcef/renderer/extensions/extensions_dispatcher_delegate.h" #include "libcef/renderer/extensions/extensions_renderer_client.h" #include "libcef/renderer/extensions/print_web_view_helper_delegate.h" +#include "libcef/renderer/media/cef_key_systems.h" #include "libcef/renderer/pepper/pepper_helper.h" #include "libcef/renderer/render_frame_observer.h" #include "libcef/renderer/render_message_filter.h" @@ -649,6 +650,11 @@ CefContentRendererClient::CreateBrowserPluginDelegate( } } +void CefContentRendererClient::AddKeySystems( + std::vector* key_systems) { + AddCefKeySystems(key_systems); +} + void CefContentRendererClient::WillDestroyCurrentMessageLoop() { base::AutoLock lock_scope(single_process_cleanup_lock_); single_process_cleanup_complete_ = true; diff --git a/libcef/renderer/content_renderer_client.h b/libcef/renderer/content_renderer_client.h index f5ab58576..40a81762e 100644 --- a/libcef/renderer/content_renderer_client.h +++ b/libcef/renderer/content_renderer_client.h @@ -108,6 +108,7 @@ class CefContentRendererClient : public content::ContentRendererClient, content::RenderFrame* render_frame, const std::string& mime_type, const GURL& original_url) override; + void AddKeySystems(std::vector* key_systems) override; // MessageLoop::DestructionObserver implementation. void WillDestroyCurrentMessageLoop() override; diff --git a/libcef/renderer/media/cef_key_systems.cc b/libcef/renderer/media/cef_key_systems.cc new file mode 100644 index 000000000..908bdce8f --- /dev/null +++ b/libcef/renderer/media/cef_key_systems.cc @@ -0,0 +1,141 @@ +// Copyright 2013 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 "libcef/renderer/media/cef_key_systems.h" + +#include +#include + +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/strings/string_split.h" +#include "base/strings/utf_string_conversions.h" +#include "components/cdm/renderer/widevine_key_systems.h" +#include "content/public/renderer/render_thread.h" +#include "libcef/common/cef_messages.h" +#include "media/base/eme_constants.h" + +#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. + +// The following must be after widevine_cdm_version.h. + +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) +#include +#include "base/version.h" +#endif + +using media::KeySystemInfo; +using media::SupportedCodecs; + +#if defined(ENABLE_PEPPER_CDMS) +static bool IsPepperCdmAvailable( + const std::string& pepper_type, + std::vector* additional_param_names, + std::vector* additional_param_values) { + bool is_available = false; + content::RenderThread::Get()->Send( + new CefViewHostMsg_IsInternalPluginAvailableForMimeType( + pepper_type, + &is_available, + additional_param_names, + additional_param_values)); + + return is_available; +} + +#if defined(WIDEVINE_CDM_AVAILABLE) +// This function finds "codecs" and parses the value into the vector |codecs|. +// Converts the codec strings to UTF-8 since we only expect ASCII strings and +// this simplifies the rest of the code in this file. +void GetSupportedCodecsForPepperCdm( + const std::vector& additional_param_names, + const std::vector& additional_param_values, + std::vector* codecs) { + DCHECK(codecs->empty()); + DCHECK_EQ(additional_param_names.size(), additional_param_values.size()); + for (size_t i = 0; i < additional_param_names.size(); ++i) { + if (additional_param_names[i] == + base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) { + const base::string16& codecs_string16 = additional_param_values[i]; + std::string codecs_string; + if (!base::UTF16ToUTF8(codecs_string16.c_str(), + codecs_string16.length(), + &codecs_string)) { + DLOG(WARNING) << "Non-UTF-8 codecs string."; + // Continue using the best effort conversion. + } + *codecs = base::SplitString( + codecs_string, std::string(1, kCdmSupportedCodecsValueDelimiter), + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + break; + } + } +} + +static void AddPepperBasedWidevine( + std::vector* concrete_key_systems) { +#if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) + Version glibc_version(gnu_get_libc_version()); + DCHECK(glibc_version.IsValid()); + if (glibc_version.IsOlderThan(WIDEVINE_CDM_MIN_GLIBC_VERSION)) + return; +#endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) + + std::vector additional_param_names; + std::vector additional_param_values; + if (!IsPepperCdmAvailable(kWidevineCdmPluginMimeType, + &additional_param_names, + &additional_param_values)) { + DVLOG(1) << "Widevine CDM is not currently available."; + return; + } + + std::vector codecs; + GetSupportedCodecsForPepperCdm(additional_param_names, + additional_param_values, + &codecs); + + SupportedCodecs supported_codecs = media::EME_CODEC_NONE; + + // Audio codecs are always supported. + // TODO(sandersd): Distinguish these from those that are directly supported, + // as those may offer a higher level of protection. + supported_codecs |= media::EME_CODEC_WEBM_OPUS; + supported_codecs |= media::EME_CODEC_WEBM_VORBIS; +#if defined(USE_PROPRIETARY_CODECS) + supported_codecs |= media::EME_CODEC_MP4_AAC; +#endif // defined(USE_PROPRIETARY_CODECS) + + for (size_t i = 0; i < codecs.size(); ++i) { + if (codecs[i] == kCdmSupportedCodecVp8) + supported_codecs |= media::EME_CODEC_WEBM_VP8; + if (codecs[i] == kCdmSupportedCodecVp9) + supported_codecs |= media::EME_CODEC_WEBM_VP9; +#if defined(USE_PROPRIETARY_CODECS) + if (codecs[i] == kCdmSupportedCodecAvc1) + supported_codecs |= media::EME_CODEC_MP4_AVC1; +#endif // defined(USE_PROPRIETARY_CODECS) + } + + cdm::AddWidevineWithCodecs( + cdm::WIDEVINE, supported_codecs, + media::EmeRobustness::SW_SECURE_CRYPTO, // Maximum audio robustness. + media::EmeRobustness::SW_SECURE_DECODE, // Maximum video robustness. + media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent-license. + media::EmeSessionTypeSupport:: + NOT_SUPPORTED, // persistent-release-message. + media::EmeFeatureSupport::REQUESTABLE, // Persistent state. + media::EmeFeatureSupport::NOT_SUPPORTED, // Distinctive identifier. + concrete_key_systems); +} +#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // defined(ENABLE_PEPPER_CDMS) + +void AddCefKeySystems(std::vector* key_systems_info) { +#if defined(ENABLE_PEPPER_CDMS) +#if defined(WIDEVINE_CDM_AVAILABLE) + AddPepperBasedWidevine(key_systems_info); +#endif // defined(WIDEVINE_CDM_AVAILABLE) +#endif // defined(ENABLE_PEPPER_CDMS) +} diff --git a/libcef/renderer/media/cef_key_systems.h b/libcef/renderer/media/cef_key_systems.h new file mode 100644 index 000000000..aafff1bbe --- /dev/null +++ b/libcef/renderer/media/cef_key_systems.h @@ -0,0 +1,14 @@ +// Copyright 2013 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 CEF_LIBCEF_RENDERER_MEDIA_CEF_KEY_SYSTEMS_H_ +#define CEF_LIBCEF_RENDERER_MEDIA_CEF_KEY_SYSTEMS_H_ + +#include + +#include "media/base/key_system_info.h" + +void AddCefKeySystems(std::vector* key_systems_info); + +#endif // CEF_LIBCEF_RENDERER_MEDIA_CEF_KEY_SYSTEMS_H_ diff --git a/tools/make_distrib.py b/tools/make_distrib.py index d8fc3cd19..a87699fb9 100644 --- a/tools/make_distrib.py +++ b/tools/make_distrib.py @@ -423,6 +423,7 @@ if platform == 'windows': 'libGLESv2.dll', 'natives_blob.bin', 'snapshot_blob.bin', + 'widevinecdmadapter.dll', ] if not options.x64build: binaries.append('wow_helper.exe')