widevine: Use component updater with the Alloy runtime (fixes issue #3149)

Widevine CDM binaries will be downloaded on supported platforms shortly after
application startup. Widevine support will then become available within a few
seconds after successful installation on Windows or after the next application
restart on other platforms. The CDM files will be downloaded to a "WidevineCdm"
directory inside the `CefSettings.user_data_path` directory.

Pass the `--disable-component-update` command-line flag to disable Widevine
download and installation. Pass the `--component-updater=fast-update` command-
line flag to force Widevine download immediately after application startup.

See the related issue for additional usage details.
This commit is contained in:
Marshall Greenblatt
2021-08-09 17:18:43 -04:00
parent eaf581e544
commit 240b869db5
45 changed files with 201 additions and 1459 deletions

View File

@@ -27,6 +27,8 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/media/cdm_registration.h"
#include "content/public/common/cdm_info.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/pepper_plugin_info.h"
@@ -35,8 +37,8 @@
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#if defined(OS_LINUX)
#include "libcef/common/widevine_loader.h"
#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
#include "chrome/common/media/cdm_host_file_path.h"
#endif
namespace {
@@ -95,10 +97,12 @@ void AlloyContentClient::AddPepperPlugins(
void AlloyContentClient::AddContentDecryptionModules(
std::vector<content::CdmInfo>* cdms,
std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
#if defined(OS_LINUX)
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
CefWidevineLoader::AddContentDecryptionModules(cdms, cdm_host_file_paths);
#endif
if (cdms)
RegisterCdmInfo(cdms);
#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
if (cdm_host_file_paths)
AddCdmHostFilePaths(cdm_host_file_paths);
#endif
}

View File

@@ -29,6 +29,7 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/utility/chrome_content_utility_client.h"
#include "components/component_updater/component_updater_paths.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/embedder_support/switches.h"
#include "components/viz/common/features.h"
@@ -369,9 +370,10 @@ void AlloyMainDelegate::PreSandboxStartup() {
#endif
resource_util::OverrideDefaultDownloadDir();
resource_util::OverrideUserDataDir(settings_, command_line);
}
resource_util::OverrideUserDataDir(settings_, command_line);
if (command_line->HasSwitch(switches::kDisablePackLoading))
resource_bundle_delegate_.set_pack_loading_disabled(true);
@@ -379,6 +381,11 @@ void AlloyMainDelegate::PreSandboxStartup() {
// chrome::DIR_CRASH_DUMPS must be configured before calling this function.
crash_reporting::PreSandboxStartup(*command_line, process_type);
// Register the component_updater PathProvider.
component_updater::RegisterPathProvider(chrome::DIR_COMPONENTS,
chrome::DIR_INTERNAL_PLUGINS,
chrome::DIR_USER_DATA);
InitializeResourceBundle();
MaybeInitializeGDI();
}

View File

@@ -7,7 +7,6 @@
#include "libcef/browser/alloy/chrome_browser_process_alloy.h"
#include "libcef/common/alloy/alloy_main_delegate.h"
#include "libcef/common/widevine_loader.h"
#include "libcef/renderer/alloy/alloy_content_renderer_client.h"
#include "content/public/browser/render_process_host.h"
@@ -38,10 +37,6 @@ void AlloyMainRunnerDelegate::BeforeMainThreadRun() {
}
void AlloyMainRunnerDelegate::AfterUIThreadInitialize() {
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
CefWidevineLoader::GetInstance()->OnContextInitialized();
#endif
static_cast<ChromeBrowserProcessAlloy*>(g_browser_process)
->OnContextInitialized();
}

View File

@@ -94,9 +94,6 @@ const char kDisableScrollBounce[] = "disable-scroll-bounce";
// Disable the PDF extension.
const char kDisablePdfExtension[] = "disable-pdf-extension";
// Path to Widevine CDM binaries.
const char kWidevineCdmPath[] = "widevine-cdm-path";
// Default plugin policy action.
const char kPluginPolicy[] = "plugin-policy";
// Allow the content. This is the default value.

View File

@@ -44,7 +44,6 @@ extern const char kEnableSpellingService[];
extern const char kOverrideSpellCheckLang[];
extern const char kDisableScrollBounce[];
extern const char kDisablePdfExtension[];
extern const char kWidevineCdmPath[];
extern const char kPluginPolicy[];
extern const char kPluginPolicy_Allow[];
extern const char kPluginPolicy_Detect[];

View File

@@ -1,513 +0,0 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions 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/common/widevine_loader.h"
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "libcef/browser/context.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_switches.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/json/json_string_value_serializer.h"
#include "base/memory/ptr_util.h"
#include "base/native_library.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/plugin_service_impl.h"
#include "content/public/browser/cdm_registry.h"
#include "content/public/common/cdm_info.h"
#include "content/public/common/content_switches.h"
#include "media/cdm/cdm_host_file.h"
#include "media/cdm/supported_cdm_versions.h"
#include "sandbox/policy/switches.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h" // nogncheck
namespace {
base::LazyInstance<CefWidevineLoader>::Leaky g_widevine_loader =
LAZY_INSTANCE_INITIALIZER;
// Based on chrome/browser/component_updater/widevine_cdm_component_installer.cc
// Name of the Widevine CDM OS in the component manifest.
const char kWidevineCdmOs[] =
#if defined(OS_MAC)
"mac";
#elif defined(OS_WIN)
"win";
#else // OS_LINUX, etc. TODO(viettrungluu): Separate out Chrome OS and Android?
"linux";
#endif
// Name of the Widevine CDM architecture in the component manifest.
const char kWidevineCdmArch[] =
#if defined(ARCH_CPU_X86)
"ia32"; // This differs from the component updater which uses "x86".
#elif defined(ARCH_CPU_X86_64)
"x64";
#elif defined(ARCH_CPU_ARM64)
"arm64";
#else
"???";
#endif
// The CDM OS and architecture.
const char kCdmOsName[] = "os";
const char kCdmArchName[] = "arch";
// The CDM version (e.g. "1.4.8.903").
const char kCdmVersionName[] = "version";
// The CDM manifest includes several custom values, all beginning with "x-cdm-".
// All values are strings.
// All values that are lists are delimited by commas. No trailing commas.
// For example, "1,2,4".
const char kCdmValueDelimiter[] = ",";
// The following entries are required.
// Interface versions are lists of integers (e.g. "1" or "1,2,4").
// These are checked in this file before registering the CDM.
// All match the interface versions from content_decryption_module.h that the
// CDM supports.
// Matches CDM_MODULE_VERSION.
const char kCdmModuleVersionsName[] = "x-cdm-module-versions";
// Matches supported ContentDecryptionModule_* version(s).
const char kCdmInterfaceVersionsName[] = "x-cdm-interface-versions";
// Matches supported Host_* version(s).
const char kCdmHostVersionsName[] = "x-cdm-host-versions";
// The codecs list is a list of simple codec names (e.g. "vp8,vorbis").
// The list is passed to other parts of Chrome.
const char kCdmCodecsListName[] = "x-cdm-codecs";
// Whether persistent license is supported by the CDM: "true" or "false".
const char kCdmPersistentLicenseSupportName[] =
"x-cdm-persistent-license-support";
const char kCdmSupportedEncryptionSchemesName[] =
"x-cdm-supported-encryption-schemes";
// The following strings are used to specify supported codecs in the
// parameter |kCdmCodecsListName|.
const char kCdmSupportedCodecVp8[] = "vp8";
const char kCdmSupportedCodecVp9[] = "vp09";
const char kCdmSupportedCodecAv1[] = "av01";
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
const char kCdmSupportedCodecAvc1[] = "avc1";
#endif
// The following strings are used to specify supported encryption schemes in
// the parameter |kCdmSupportedEncryptionSchemesName|.
const char kCdmSupportedEncryptionSchemeCenc[] = "cenc";
const char kCdmSupportedEncryptionSchemeCbcs[] = "cbcs";
// Arguments passed to MakeCdmInfo.
struct CdmInfoArgs {
base::FilePath path;
std::string version;
media::CdmCapability capability;
};
std::unique_ptr<base::DictionaryValue> ParseManifestFile(
const base::FilePath& manifest_path) {
CEF_REQUIRE_BLOCKING();
// Manifest file should be < 1kb. Read at most 2kb.
std::string manifest_contents;
if (!base::ReadFileToStringWithMaxSize(manifest_path, &manifest_contents,
2048)) {
return nullptr;
}
JSONStringValueDeserializer deserializer(manifest_contents);
std::unique_ptr<base::Value> manifest(
deserializer.Deserialize(nullptr, nullptr));
if (!manifest.get() || !manifest->is_dict())
return nullptr;
// Transfer ownership to the caller.
return base::WrapUnique(
static_cast<base::DictionaryValue*>(manifest.release()));
}
std::string GetManifestValue(const base::DictionaryValue& manifest,
const std::string& key,
std::string* error_message) {
std::stringstream ss;
std::string value;
if (!manifest.GetString(key, &value)) {
ss << "Manifest missing " << key;
*error_message = ss.str();
} else if (value.empty()) {
ss << "Manifest has empty " << key;
*error_message = ss.str();
}
return value;
}
typedef bool (*VersionCheckFunc)(int version);
bool CheckForCompatibleVersion(const base::DictionaryValue& manifest,
const std::string version_name,
VersionCheckFunc version_check_func,
std::string* error_message) {
std::string versions_string =
GetManifestValue(manifest, version_name, error_message);
if (versions_string.empty())
return false;
for (const base::StringPiece& ver_str :
base::SplitStringPiece(versions_string, kCdmValueDelimiter,
base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
int version = 0;
if (base::StringToInt(ver_str, &version))
if (version_check_func(version))
return true;
}
std::stringstream ss;
ss << "Manifest has no supported " << version_name << " in '"
<< versions_string << "'";
*error_message = ss.str();
return false;
}
// Returns whether the CDM's OS/platform and module/interface/host API versions,
// as specified in the manifest, are compatible with this Chromium binary.
bool IsCompatibleWithChrome(const base::DictionaryValue& manifest,
std::string* error_message) {
return GetManifestValue(manifest, kCdmOsName, error_message) ==
kWidevineCdmOs &&
GetManifestValue(manifest, kCdmArchName, error_message) ==
kWidevineCdmArch &&
CheckForCompatibleVersion(manifest, kCdmModuleVersionsName,
media::IsSupportedCdmModuleVersion,
error_message) &&
CheckForCompatibleVersion(manifest, kCdmInterfaceVersionsName,
media::IsSupportedCdmInterfaceVersion,
error_message) &&
CheckForCompatibleVersion(manifest, kCdmHostVersionsName,
media::IsSupportedCdmHostVersion,
error_message);
}
// Returns true and updates |video_codecs| if the appropriate manifest entry is
// valid. Returns false and does not modify |video_codecs| if the manifest entry
// is incorrectly formatted.
bool GetCodecs(const base::DictionaryValue& manifest,
media::CdmCapability::VideoCodecMap* video_codecs,
std::string* error_message) {
DCHECK(video_codecs);
const base::Value* value = manifest.FindKey(kCdmCodecsListName);
if (!value) {
std::stringstream ss;
ss << "Widevine CDM component manifest is missing codecs.";
*error_message = ss.str();
return true;
}
if (!value->is_string()) {
std::stringstream ss;
ss << "Manifest entry " << kCdmCodecsListName << " is not a string.";
*error_message = ss.str();
return false;
}
const std::string& codecs = value->GetString();
if (codecs.empty()) {
std::stringstream ss;
ss << "Widevine CDM component manifest has empty codecs list.";
*error_message = ss.str();
return true;
}
media::CdmCapability::VideoCodecMap result;
const std::vector<media::VideoCodecProfile> kAllProfiles = {};
const std::vector<base::StringPiece> supported_codecs =
base::SplitStringPiece(codecs, kCdmValueDelimiter, base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY);
for (const auto& codec : supported_codecs) {
if (codec == kCdmSupportedCodecVp8)
result.emplace(media::VideoCodec::kCodecVP8, kAllProfiles);
else if (codec == kCdmSupportedCodecVp9)
result.emplace(media::VideoCodec::kCodecVP9, kAllProfiles);
else if (codec == kCdmSupportedCodecAv1)
result.emplace(media::VideoCodec::kCodecAV1, kAllProfiles);
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
else if (codec == kCdmSupportedCodecAvc1)
result.emplace(media::VideoCodec::kCodecH264, kAllProfiles);
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
}
video_codecs->swap(result);
return true;
}
// Returns true and updates |encryption_schemes| if the appropriate manifest
// entry is valid. Returns false and does not modify |encryption_schemes| if the
// manifest entry is incorrectly formatted. It is assumed that all CDMs support
// 'cenc', so if the manifest entry is missing, the result will indicate support
// for 'cenc' only. Incorrect types in the manifest entry will log the error and
// fail. Unrecognized values will be reported but otherwise ignored.
bool GetEncryptionSchemes(
const base::DictionaryValue& manifest,
base::flat_set<media::EncryptionScheme>* encryption_schemes,
std::string* error_message) {
DCHECK(encryption_schemes);
const base::Value* value =
manifest.FindKey(kCdmSupportedEncryptionSchemesName);
if (!value) {
// No manifest entry found, so assume only 'cenc' supported for backwards
// compatibility.
encryption_schemes->insert(media::EncryptionScheme::kCenc);
return true;
}
if (!value->is_list()) {
std::stringstream ss;
ss << "Manifest entry " << kCdmSupportedEncryptionSchemesName
<< " is not a list.";
*error_message = ss.str();
return false;
}
const base::span<const base::Value> list = value->GetList();
base::flat_set<media::EncryptionScheme> result;
for (const auto& item : list) {
if (!item.is_string()) {
std::stringstream ss;
ss << "Unrecognized item type in manifest entry "
<< kCdmSupportedEncryptionSchemesName;
*error_message = ss.str();
return false;
}
const std::string& scheme = item.GetString();
if (scheme == kCdmSupportedEncryptionSchemeCenc) {
result.insert(media::EncryptionScheme::kCenc);
} else if (scheme == kCdmSupportedEncryptionSchemeCbcs) {
result.insert(media::EncryptionScheme::kCbcs);
} else {
std::stringstream ss;
ss << "Unrecognized encryption scheme " << scheme << " in manifest entry "
<< kCdmSupportedEncryptionSchemesName;
*error_message = ss.str();
}
}
// As the manifest entry exists, it must specify at least one valid value.
if (result.empty())
return false;
encryption_schemes->swap(result);
return true;
}
// Returns true and updates |session_types| if the appropriate manifest entry is
// valid. Returns false if the manifest entry is incorrectly formatted.
bool GetSessionTypes(const base::DictionaryValue& manifest,
base::flat_set<media::CdmSessionType>* session_types,
std::string* error_message) {
DCHECK(session_types);
bool is_persistent_license_supported = false;
const base::Value* value = manifest.FindKey(kCdmPersistentLicenseSupportName);
if (value) {
if (!value->is_bool())
return false;
is_persistent_license_supported = value->GetBool();
}
// Temporary session is always supported.
session_types->insert(media::CdmSessionType::kTemporary);
if (is_persistent_license_supported)
session_types->insert(media::CdmSessionType::kPersistentLicense);
return true;
}
// Verify and load the contents of |base_path|.
cef_cdm_registration_error_t LoadWidevineCdmInfo(
const base::FilePath& base_path,
CdmInfoArgs* args,
std::string* error_message) {
std::stringstream ss;
args->path = base_path.AppendASCII(
base::GetNativeLibraryName(kWidevineCdmLibraryName));
if (!base::PathExists(args->path)) {
ss << "Missing file " << args->path.value();
*error_message = ss.str();
return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS;
}
base::FilePath manifest_path = base_path.AppendASCII("manifest.json");
if (!base::PathExists(manifest_path)) {
ss << "Missing manifest file " << manifest_path.value();
*error_message = ss.str();
return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS;
}
std::unique_ptr<base::DictionaryValue> manifest =
ParseManifestFile(manifest_path);
if (!manifest) {
ss << "Failed to parse manifest file " << manifest_path.value();
*error_message = ss.str();
return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS;
}
if (!IsCompatibleWithChrome(*manifest, error_message))
return CEF_CDM_REGISTRATION_ERROR_INCOMPATIBLE;
args->version = GetManifestValue(*manifest, kCdmVersionName, error_message);
if (args->version.empty())
return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS;
if (!GetCodecs(*manifest, &args->capability.video_codecs, error_message) ||
!GetEncryptionSchemes(*manifest, &args->capability.encryption_schemes,
error_message) ||
!GetSessionTypes(*manifest, &args->capability.session_types,
error_message)) {
return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS;
}
return CEF_CDM_REGISTRATION_ERROR_NONE;
}
void DeliverWidevineCdmCallback(cef_cdm_registration_error_t result,
const std::string& error_message,
CefRefPtr<CefRegisterCdmCallback> callback) {
CEF_REQUIRE_UIT();
if (result != CEF_CDM_REGISTRATION_ERROR_NONE)
LOG(ERROR) << "Widevine CDM registration failed; " << error_message;
else if (!error_message.empty())
LOG(WARNING) << "Widevine CDM registration warning; " << error_message;
if (callback)
callback->OnCdmRegistrationComplete(result, error_message);
}
content::CdmInfo MakeCdmInfo(const CdmInfoArgs& args) {
return content::CdmInfo(
kWidevineKeySystem, content::CdmInfo::Robustness::kSoftwareSecure,
std::move(args.capability), /*supports_sub_key_systems=*/false,
kWidevineCdmDisplayName, kWidevineCdmGuid, base::Version(args.version),
args.path, kWidevineCdmFileSystemId);
}
void RegisterWidevineCdmOnUIThread(std::unique_ptr<CdmInfoArgs> args,
CefRefPtr<CefRegisterCdmCallback> callback) {
CEF_REQUIRE_UIT();
// Register Widevine with the CdmRegistry.
content::CdmRegistry::GetInstance()->RegisterCdm(MakeCdmInfo(*args));
DeliverWidevineCdmCallback(CEF_CDM_REGISTRATION_ERROR_NONE, std::string(),
callback);
}
void LoadWidevineCdmInfoOnBlockingThread(
const base::FilePath& base_path,
CefRefPtr<CefRegisterCdmCallback> callback) {
CEF_REQUIRE_BLOCKING();
std::unique_ptr<CdmInfoArgs> args = std::make_unique<CdmInfoArgs>();
std::string error_message;
cef_cdm_registration_error_t result =
LoadWidevineCdmInfo(base_path, args.get(), &error_message);
if (result != CEF_CDM_REGISTRATION_ERROR_NONE) {
CEF_POST_TASK(CEF_UIT, base::BindOnce(DeliverWidevineCdmCallback, result,
error_message, callback));
return;
}
// Continue execution on the UI thread.
CEF_POST_TASK(CEF_UIT, base::BindOnce(RegisterWidevineCdmOnUIThread,
std::move(args), callback));
}
} // namespace
// static
CefWidevineLoader* CefWidevineLoader::GetInstance() {
return &g_widevine_loader.Get();
}
void CefWidevineLoader::LoadWidevineCdm(
const base::FilePath& path,
CefRefPtr<CefRegisterCdmCallback> callback) {
if (!CONTEXT_STATE_VALID()) {
// Loading will proceed from OnContextInitialized().
load_pending_ = true;
path_ = path;
callback_ = callback;
return;
}
CEF_POST_USER_VISIBLE_TASK(
base::BindOnce(LoadWidevineCdmInfoOnBlockingThread, path, callback));
}
void CefWidevineLoader::OnContextInitialized() {
CEF_REQUIRE_UIT();
if (load_pending_) {
load_pending_ = false;
LoadWidevineCdm(path_, callback_);
callback_ = nullptr;
}
}
#if defined(OS_LINUX)
// static
void CefWidevineLoader::AddContentDecryptionModules(
std::vector<content::CdmInfo>* cdms,
std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
// Perform early plugin registration in the zygote process when the sandbox is
// enabled to avoid "cannot open shared object file: Operation not permitted"
// errors during plugin loading. This is because the Zygote process must pre-
// load all plugins before initializing the sandbox.
if (command_line.GetSwitchValueASCII(switches::kProcessType) !=
switches::kZygoteProcess ||
command_line.HasSwitch(sandbox::policy::switches::kNoSandbox)) {
return;
}
// The Widevine CDM path is passed to the zygote process via
// AlloyContentBrowserClient::AppendExtraCommandLineSwitches.
const base::FilePath& base_path =
command_line.GetSwitchValuePath(switches::kWidevineCdmPath);
if (base_path.empty())
return;
// Load contents of the plugin directory synchronously. This only occurs once
// on zygote process startup so should not have a huge performance penalty.
CdmInfoArgs args;
std::string error_message;
cef_cdm_registration_error_t result =
LoadWidevineCdmInfo(base_path, &args, &error_message);
if (result != CEF_CDM_REGISTRATION_ERROR_NONE) {
LOG(ERROR) << "Widevine CDM registration failed; " << error_message;
return;
}
cdms->push_back(MakeCdmInfo(args));
}
#endif // defined(OS_LINUX)
CefWidevineLoader::CefWidevineLoader() {}
CefWidevineLoader::~CefWidevineLoader() {}
#endif // BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)

View File

@@ -1,70 +0,0 @@
// Copyright 2016 The Chromium Embedded Framework 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_COMMON_WIDEVINE_LOADER_H_
#define CEF_LIBCEF_COMMON_WIDEVINE_LOADER_H_
#pragma once
#include "build/build_config.h"
#include "media/media_buildflags.h"
#include "third_party/widevine/cdm/buildflags.h"
#if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include <vector>
#include "include/cef_web_plugin.h"
#include "base/lazy_instance.h"
namespace content {
struct CdmInfo;
}
namespace media {
struct CdmHostFilePath;
}
class CefWidevineLoader {
public:
// Returns the singleton instance of this object.
static CefWidevineLoader* GetInstance();
// Load the Widevine CDM. May be called before or after context creation. See
// comments in cef_web_plugin.h.
void LoadWidevineCdm(const base::FilePath& path,
CefRefPtr<CefRegisterCdmCallback> callback);
// Plugin registration is triggered here if LoadWidevineCdm() was called
// before context creation.
void OnContextInitialized();
#if defined(OS_LINUX)
// The zygote process which is used when the sandbox is enabled on Linux
// requires early loading of CDM modules. Other processes will receive
// load notification in the usual way.
// Called from AlloyContentClient::AddContentDecryptionModules.
static void AddContentDecryptionModules(
std::vector<content::CdmInfo>* cdms,
std::vector<media::CdmHostFilePath>* cdm_host_file_paths);
const base::FilePath& path() { return path_; }
#endif
private:
friend struct base::LazyInstanceTraitsBase<CefWidevineLoader>;
// Members are only accessed before context initialization or on the UI
// thread.
bool load_pending_ = false;
base::FilePath path_;
CefRefPtr<CefRegisterCdmCallback> callback_;
CefWidevineLoader();
~CefWidevineLoader();
};
#endif // BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS)
#endif // CEF_LIBCEF_COMMON_WIDEVINE_LOADER_H_