diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/media/cdm | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) | |
download | qtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/media/cdm')
27 files changed, 747 insertions, 171 deletions
diff --git a/chromium/media/cdm/BUILD.gn b/chromium/media/cdm/BUILD.gn index 05d5df585d1..a267535f983 100644 --- a/chromium/media/cdm/BUILD.gn +++ b/chromium/media/cdm/BUILD.gn @@ -60,10 +60,6 @@ source_set("cdm") { deps += [ ":cdm_api", ":cdm_paths", - - # TODO(xhwang): Remove this after Widevine specific logic is removed in - # CdmAdapterFactory. See http://crbug.com/510604 - "//third_party/widevine/cdm:headers", ] sources += [ "cdm_adapter.cc", @@ -88,6 +84,21 @@ source_set("cdm") { "supported_cdm_versions.cc", "supported_cdm_versions.h", ] + + if (enable_cdm_host_verification) { + sources += [ + "cdm_host_file.cc", + "cdm_host_file.h", + "cdm_host_files.cc", + "cdm_host_files.h", + ] + deps += [ + # Needed for finding CDM path from CDM adapter path. + # TODO(xhwang): Remove this dependency when CDM adapter is deprecated. + # See http://crbug.com/403462 + "//third_party/widevine/cdm:headers", + ] + } } } diff --git a/chromium/media/cdm/aes_decryptor_unittest.cc b/chromium/media/cdm/aes_decryptor_unittest.cc index b24422eee19..90a5a298422 100644 --- a/chromium/media/cdm/aes_decryptor_unittest.cc +++ b/chromium/media/cdm/aes_decryptor_unittest.cc @@ -59,7 +59,7 @@ MATCHER(NotEmpty, "") { MATCHER(IsJSONDictionary, "") { std::string result(arg.begin(), arg.end()); std::unique_ptr<base::Value> root(base::JSONReader().ReadToValue(result)); - return (root.get() && root->GetType() == base::Value::Type::DICTIONARY); + return (root.get() && root->type() == base::Value::Type::DICTIONARY); } MATCHER(IsNullTime, "") { return arg.is_null(); @@ -279,7 +279,12 @@ class AesDecryptorTest : public testing::TestWithParam<TestType> { {}); helper_.reset(new ExternalClearKeyTestHelper()); - CdmModule::GetInstance()->SetCdmPathForTesting(helper_->LibraryPath()); + +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + CdmModule::GetInstance()->Initialize(helper_->LibraryPath(), {}); +#else + CdmModule::GetInstance()->Initialize(helper_->LibraryPath()); +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) std::unique_ptr<CdmAllocator> allocator(new SimpleCdmAllocator()); std::unique_ptr<CdmAuxiliaryHelper> cdm_helper( diff --git a/chromium/media/cdm/api/codereview.settings b/chromium/media/cdm/api/codereview.settings index 9faf2326bf1..455942aff1b 100644 --- a/chromium/media/cdm/api/codereview.settings +++ b/chromium/media/cdm/api/codereview.settings @@ -1,9 +1,7 @@ -CODE_REVIEW_SERVER: codereview.chromium.org +# This file is used by git-cl to get repository specific information. CC_LIST: cdm-api-reviews@chromium.org, feature-media-reviews@chromium.org -VIEW_VC: https://chromium.googlesource.com/chromium/cdm/+/ +CODE_REVIEW_SERVER: codereview.chromium.org +GERRIT_HOST: True +PROJECT: cdm STATUS: http://chromium-status.appspot.com/status -TRY_ON_UPLOAD: False -TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try -GITCL_PREUPLOAD: http://src.chromium.org/viewvc/chrome/trunk/tools/depot_tools/git-cl-upload-hook?revision=HEAD -GITCL_PREDCOMMIT: http://src.chromium.org/viewvc/chrome/trunk/tools/depot_tools/git-cl-upload-hook?revision=HEAD -PROJECT: chromium_deps +VIEW_VC: https://chromium.googlesource.com/chromium/cdm/+/ diff --git a/chromium/media/cdm/api/content_decryption_module.h b/chromium/media/cdm/api/content_decryption_module.h index 8b549b3c22e..431ca67409f 100644 --- a/chromium/media/cdm/api/content_decryption_module.h +++ b/chromium/media/cdm/api/content_decryption_module.h @@ -73,12 +73,12 @@ CDM_API const char* GetCdmVersion(); namespace cdm { -class AudioFrames; -class DecryptedBlock; -class VideoFrame; +class CDM_CLASS_API AudioFrames; +class CDM_CLASS_API DecryptedBlock; +class CDM_CLASS_API VideoFrame; -class Host_8; -class Host_9; +class CDM_CLASS_API Host_8; +class CDM_CLASS_API Host_9; enum Status { kSuccess = 0, @@ -799,8 +799,8 @@ class CDM_CLASS_API ContentDecryptionModule_9 { // // Returns kSuccess if the |audio_decoder_config| is supported and the CDM // audio decoder is successfully initialized. - // Returns kSessionError if |audio_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). + // Returns kInitializationError if |audio_decoder_config| is not supported. + // The CDM may still be able to do Decrypt(). // Returns kDeferredInitialization if the CDM is not ready to initialize the // decoder at this time. Must call Host::OnDeferredInitializationDone() once // initialization is complete. @@ -812,8 +812,8 @@ class CDM_CLASS_API ContentDecryptionModule_9 { // // Returns kSuccess if the |video_decoder_config| is supported and the CDM // video decoder is successfully initialized. - // Returns kSessionError if |video_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). + // Returns kInitializationError if |video_decoder_config| is not supported. + // The CDM may still be able to do Decrypt(). // Returns kDeferredInitialization if the CDM is not ready to initialize the // decoder at this time. Must call Host::OnDeferredInitializationDone() once // initialization is complete. @@ -883,9 +883,16 @@ class CDM_CLASS_API ContentDecryptionModule_9 { uint32_t link_mask, uint32_t output_protection_mask) = 0; - // Called by the host after a call to Host::RequestStorageId(). If the storage - // ID is not available, null/zero will be provided. - virtual void OnStorageId(const uint8_t* storage_id, + // Called by the host after a call to Host::RequestStorageId(). If the + // version of the storage ID requested is available, |storage_id| and + // |storage_id_size| are set appropriately. |version| will be the same as + // what was requested, unless 0 (latest) was requested, in which case + // |version| will be the actual version number for the |storage_id| returned. + // If the requested version is not available, null/zero will be provided as + // |storage_id| and |storage_id_size|, respectively, and |version| should be + // ignored. + virtual void OnStorageId(uint32_t version, + const uint8_t* storage_id, uint32_t storage_id_size) = 0; // Destroys the object in the same context as it was created. @@ -1176,11 +1183,14 @@ class CDM_CLASS_API Host_9 { // CDM can call this method multiple times to operate on different files. virtual FileIO* CreateFileIO(FileIOClient* client) = 0; - // Requests the storage ID. The ID will be returned by the host via - // ContentDecryptionModule::OnStorageId(). A storage ID is a stable, device - // specific ID used by the CDM to securely store persistent data. The CDM must - // not expose the ID outside the client device, even in encrypted form. - virtual void RequestStorageId() = 0; + // Requests a specific version of the storage ID. A storage ID is a stable, + // device specific ID used by the CDM to securely store persistent data. The + // ID will be returned by the host via ContentDecryptionModule::OnStorageId(). + // If |version| is 0, the latest version will be returned. On some systems + // storage ID is not implemented, so the response will be |storage_id| = null. + // The CDM must not expose the ID outside the client device, even in encrypted + // form. + virtual void RequestStorageId(uint32_t version) = 0; protected: Host_9() {} diff --git a/chromium/media/cdm/cdm_adapter.cc b/chromium/media/cdm/cdm_adapter.cc index 6b5fb3ffb5f..e0e96d7cd63 100644 --- a/chromium/media/cdm/cdm_adapter.cc +++ b/chromium/media/cdm/cdm_adapter.cc @@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" +#include "base/metrics/histogram_macros.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "media/base/audio_decoder_config.h" @@ -435,10 +436,9 @@ CdmAdapter::~CdmAdapter() {} CdmWrapper* CdmAdapter::CreateCdmInstance(const std::string& key_system) { DCHECK(task_runner_->BelongsToCurrentThread()); - CreateCdmFunc create_cdm_func = - CdmModule::GetInstance()->GetCreateCdmFunc(key_system); + CreateCdmFunc create_cdm_func = CdmModule::GetInstance()->GetCreateCdmFunc(); if (!create_cdm_func) { - DVLOG(1) << "Cannot get CreateCdmFunc for " + key_system; + LOG(ERROR) << "Failed to get CreateCdmFunc!"; return nullptr; } @@ -446,6 +446,16 @@ CdmWrapper* CdmAdapter::CreateCdmInstance(const std::string& key_system) { key_system.size(), GetCdmHost, this); DVLOG(1) << "CDM instance for " + key_system + (cdm ? "" : " could not be") + " created."; + + if (cdm) { + // The interface version is relatively small. So using normal histogram + // instead of a sparse histogram is okay. The following DCHECK asserts this. + DCHECK(cdm->GetInterfaceVersion() <= 30); + UMA_HISTOGRAM_ENUMERATION("Media.EME.CdmInterfaceVersion", + cdm->GetInterfaceVersion(), + cdm::ContentDecryptionModule::kVersion + 1); + } + return cdm; } @@ -1014,13 +1024,14 @@ cdm::FileIO* CdmAdapter::CreateFileIO(cdm::FileIOClient* client) { return file_io.release(); } -void CdmAdapter::RequestStorageId() { - helper_->GetStorageId( - base::Bind(&CdmAdapter::OnStorageIdObtained, weak_factory_.GetWeakPtr())); +void CdmAdapter::RequestStorageId(uint32_t version) { + helper_->GetStorageId(version, base::Bind(&CdmAdapter::OnStorageIdObtained, + weak_factory_.GetWeakPtr())); } -void CdmAdapter::OnStorageIdObtained(const std::vector<uint8_t>& storage_id) { - cdm_->OnStorageId(storage_id.data(), storage_id.size()); +void CdmAdapter::OnStorageIdObtained(uint32_t version, + const std::vector<uint8_t>& storage_id) { + cdm_->OnStorageId(version, storage_id.data(), storage_id.size()); } bool CdmAdapter::AudioFramesDataToAudioFrames( diff --git a/chromium/media/cdm/cdm_adapter.h b/chromium/media/cdm/cdm_adapter.h index adade991045..c2ece068780 100644 --- a/chromium/media/cdm/cdm_adapter.h +++ b/chromium/media/cdm/cdm_adapter.h @@ -140,7 +140,7 @@ class MEDIA_EXPORT CdmAdapter : public ContentDecryptionModule, void OnDeferredInitializationDone(cdm::StreamType stream_type, cdm::Status decoder_status) override; cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) override; - void RequestStorageId() override; + void RequestStorageId(uint32_t version) override; // cdm::Host_8 specific implementation. void OnRejectPromise(uint32_t promise_id, @@ -195,7 +195,8 @@ class MEDIA_EXPORT CdmAdapter : public ContentDecryptionModule, const std::string& signed_data, const std::string& signed_data_signature, const std::string& platform_key_certificate); - void OnStorageIdObtained(const std::vector<uint8_t>& storage_id); + void OnStorageIdObtained(uint32_t version, + const std::vector<uint8_t>& storage_id); // Callbacks for OutputProtection. void OnOutputProtectionRequestMade(bool success); diff --git a/chromium/media/cdm/cdm_adapter_unittest.cc b/chromium/media/cdm/cdm_adapter_unittest.cc index 9ff40feb886..d8b840541ae 100644 --- a/chromium/media/cdm/cdm_adapter_unittest.cc +++ b/chromium/media/cdm/cdm_adapter_unittest.cc @@ -95,7 +95,11 @@ class CdmAdapterTest : public testing::Test { media::kSupportExperimentalCdmInterface}, {}); - CdmModule::GetInstance()->SetCdmPathForTesting(helper_.LibraryPath()); +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + CdmModule::GetInstance()->Initialize(helper_.LibraryPath(), {}); +#else + CdmModule::GetInstance()->Initialize(helper_.LibraryPath()); +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) } ~CdmAdapterTest() override { CdmModule::ResetInstanceForTesting(); } @@ -260,8 +264,16 @@ TEST_F(CdmAdapterTest, Initialize) { } TEST_F(CdmAdapterTest, BadLibraryPath) { - CdmModule::GetInstance()->SetCdmPathForTesting( + CdmModule::ResetInstanceForTesting(); + +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + CdmModule::GetInstance()->Initialize( + base::FilePath(FILE_PATH_LITERAL("no_library_here")), {}); +#else + CdmModule::GetInstance()->Initialize( base::FilePath(FILE_PATH_LITERAL("no_library_here"))); +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + InitializeAndExpect(FAILURE); } diff --git a/chromium/media/cdm/cdm_auxiliary_helper.cc b/chromium/media/cdm/cdm_auxiliary_helper.cc index 09c1983248c..74bd373cd41 100644 --- a/chromium/media/cdm/cdm_auxiliary_helper.cc +++ b/chromium/media/cdm/cdm_auxiliary_helper.cc @@ -39,8 +39,8 @@ void CdmAuxiliaryHelper::ChallengePlatform(const std::string& service_id, std::move(callback).Run(false, "", "", ""); } -void CdmAuxiliaryHelper::GetStorageId(StorageIdCB callback) { - std::move(callback).Run(std::vector<uint8_t>()); +void CdmAuxiliaryHelper::GetStorageId(uint32_t version, StorageIdCB callback) { + std::move(callback).Run(version, std::vector<uint8_t>()); } } // namespace media diff --git a/chromium/media/cdm/cdm_auxiliary_helper.h b/chromium/media/cdm/cdm_auxiliary_helper.h index 8b5a7414246..9716b07a2ea 100644 --- a/chromium/media/cdm/cdm_auxiliary_helper.h +++ b/chromium/media/cdm/cdm_auxiliary_helper.h @@ -52,7 +52,7 @@ class MEDIA_EXPORT CdmAuxiliaryHelper : public CdmAllocator, void ChallengePlatform(const std::string& service_id, const std::string& challenge, ChallengePlatformCB callback) override; - void GetStorageId(StorageIdCB callback) override; + void GetStorageId(uint32_t version, StorageIdCB callback) override; private: DISALLOW_COPY_AND_ASSIGN(CdmAuxiliaryHelper); diff --git a/chromium/media/cdm/cdm_host_file.cc b/chromium/media/cdm/cdm_host_file.cc new file mode 100644 index 00000000000..839dc5784f5 --- /dev/null +++ b/chromium/media/cdm/cdm_host_file.cc @@ -0,0 +1,57 @@ +// Copyright 2016 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 "media/cdm/cdm_host_file.h" + +#include <memory> + +#include "base/command_line.h" +#include "base/feature_list.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "media/cdm/api/content_decryption_module_ext.h" + +namespace media { + +CdmHostFilePath::CdmHostFilePath(const base::FilePath& file_path, + const base::FilePath& sig_file_path) + : file_path(file_path), sig_file_path(sig_file_path) {} + +CdmHostFilePath::~CdmHostFilePath() {} + +// static +std::unique_ptr<CdmHostFile> CdmHostFile::Create( + const base::FilePath& file_path, + const base::FilePath& sig_file_path) { + DVLOG(1) << __func__; + + // Open file at |file_path|. + base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + DVLOG(1) << " " << file.IsValid() << ": " << file_path.MaybeAsASCII(); + + // Also open the sig file at |sig_file_path|. + base::File sig_file(sig_file_path, + base::File::FLAG_OPEN | base::File::FLAG_READ); + DVLOG(1) << " " << sig_file.IsValid() << ": " + << sig_file_path.MaybeAsASCII(); + + return std::unique_ptr<CdmHostFile>( + new CdmHostFile(file_path, std::move(file), std::move(sig_file))); +} + +cdm::HostFile CdmHostFile::TakePlatformFile() { + return cdm::HostFile(file_path_.value().c_str(), file_.TakePlatformFile(), + sig_file_.TakePlatformFile()); +} + +CdmHostFile::CdmHostFile(const base::FilePath& file_path, + base::File file, + base::File sig_file) + : file_path_(file_path), + file_(std::move(file)), + sig_file_(std::move(sig_file)) { + DCHECK(!file_path_.empty()); +} + +} // namespace media diff --git a/chromium/media/cdm/cdm_host_file.h b/chromium/media/cdm/cdm_host_file.h new file mode 100644 index 00000000000..4ba0296db8a --- /dev/null +++ b/chromium/media/cdm/cdm_host_file.h @@ -0,0 +1,66 @@ +// Copyright 2016 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 MEDIA_CDM_CDM_HOST_FILE_H_ +#define MEDIA_CDM_CDM_HOST_FILE_H_ + +#include <memory> + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "media/base/media_export.h" + +namespace cdm { +struct HostFile; +} + +namespace media { + +struct MEDIA_EXPORT CdmHostFilePath { + CdmHostFilePath(const base::FilePath& file_path, + const base::FilePath& sig_file_path); + ~CdmHostFilePath(); + + // Path to a file that takes part in hosting the CDM. + base::FilePath file_path; + + // Path to a signature file of the file at |file_path|. + base::FilePath sig_file_path; +}; + +// Represents a file that participated in hosting the CDM. +class MEDIA_EXPORT CdmHostFile { + public: + // Opens the file at |file_path| and the corresponding signature file at + // |sig_file_path|. Upon success, constructs and returns a CdmHostFile object. + // Otherwise returns nullptr. The opened files are closed when |this| is + // destructed unless TakePlatformFile() was called, in which case the caller + // must make sure the files are closed properly. + static std::unique_ptr<CdmHostFile> Create( + const base::FilePath& file_path, + const base::FilePath& sig_file_path); + + // Takes the PlatformFile of the |file_| and |sig_file_| and put them in the + // returned cdm::HostFile. The caller must make sure the PlatformFiles are + // properly closed after use. + cdm::HostFile TakePlatformFile(); + + private: + CdmHostFile(const base::FilePath& file_path, + base::File file, + base::File sig_file); + + base::FilePath file_path_; + base::File file_; + + // The signature file associated with |file_|. + base::File sig_file_; + + DISALLOW_COPY_AND_ASSIGN(CdmHostFile); +}; + +} // namespace media + +#endif // MEDIA_CDM_CDM_HOST_FILE_H_ diff --git a/chromium/media/cdm/cdm_host_files.cc b/chromium/media/cdm/cdm_host_files.cc new file mode 100644 index 00000000000..ce695e7bb87 --- /dev/null +++ b/chromium/media/cdm/cdm_host_files.cc @@ -0,0 +1,240 @@ +// Copyright 2016 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 "media/cdm/cdm_host_files.h" + +#include <memory> +#include <vector> + +#include "base/command_line.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/native_library.h" +#include "base/path_service.h" +#include "base/scoped_native_library.h" +#include "build/build_config.h" +#include "media/cdm/api/content_decryption_module_ext.h" +#include "media/cdm/cdm_paths.h" + +// Needed for finding CDM path from CDM adapter path. +// TODO(crbug.com/403462): Remove this after CDM adapter is deprecated. +#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. + +namespace media { + +namespace { + +// TODO(xhwang): Move this to a common place if needed. +const base::FilePath::CharType kSignatureFileExtension[] = + FILE_PATH_LITERAL(".sig"); + +// Returns the signature file path given the |file_path|. This function should +// only be used when the signature file and the file are located in the same +// directory, which is the case for the CDM and CDM adapter. +base::FilePath GetSigFilePath(const base::FilePath& file_path) { + return file_path.AddExtension(kSignatureFileExtension); +} + +// Returns the CDM library file name given the |cdm_adapter_file_name|. Returns +// nullptr if |cdm_adapter_file_name| does not correspond to a known CDM. +const char* GetCdmFileName(const base::FilePath& cdm_adapter_file_name) { +#if defined(WIDEVINE_CDM_AVAILABLE) + if (cdm_adapter_file_name == + base::FilePath::FromUTF8Unsafe(kWidevineCdmAdapterFileName)) + return kWidevineCdmLibraryName; +#endif + + // Clear Key CDM. For test only. + if (cdm_adapter_file_name == + base::FilePath::FromUTF8Unsafe(media::kClearKeyCdmAdapterFileName)) + return media::kClearKeyCdmLibraryName; + + return nullptr; +} + +// Returns the path to the CDM binary given the |cdm_adapter_path|. Returns an +// empty path if |cdm_adapter_path| does not correspond to a known CDM. +base::FilePath GetCdmPath(const base::FilePath& cdm_adapter_path) { + const char* cdm_file_name = GetCdmFileName(cdm_adapter_path.BaseName()); + if (!cdm_file_name) + return base::FilePath(); + + return cdm_adapter_path.DirName().AppendASCII( + base::GetNativeLibraryName(cdm_file_name)); +} + +// Gets the library where InitVerificationFunc pointer can be obtained. +// TODO(crbug.com/403462): Remove this after CDM adapter is deprecated. +base::NativeLibrary GetCdmLibrary(base::NativeLibrary cdm_adapter_library, + const base::FilePath& cdm_adapter_path) { + DCHECK(cdm_adapter_library); + + base::NativeLibrary cdm_library = nullptr; + +#if defined(OS_LINUX) || defined(OS_MACOSX) + // On POSIX, "the dlsym() function shall search for the named symbol in all + // objects loaded automatically as a result of loading the object referenced + // by handle". Since the CDM is loaded automatically as a result of loading + // the CDM adapter, we can just use the adapter to look for CDM symbols. + cdm_library = cdm_adapter_library; +#elif defined(OS_WIN) + // On Windows, we have manually load the CDM. + base::ScopedNativeLibrary scoped_cdm_library; + base::NativeLibraryLoadError error; + scoped_cdm_library.Reset( + base::LoadNativeLibrary(GetCdmPath(cdm_adapter_path), &error)); + if (!scoped_cdm_library.is_valid()) + LOG(ERROR) << "Failed to load CDM (error: " << error.ToString() << ")"; + else + cdm_library = scoped_cdm_library.get(); +#endif + + return cdm_library; +} + +} // namespace + +CdmHostFiles::CdmHostFiles() { + DVLOG(1) << __func__; +} + +CdmHostFiles::~CdmHostFiles() { + DVLOG(1) << __func__; +} + +void CdmHostFiles::InitializeWithAdapter( + const base::FilePath& cdm_adapter_path, + const std::vector<CdmHostFilePath>& cdm_host_file_paths) { + OpenCdmFileWithAdapter(cdm_adapter_path); + OpenCommonFiles(cdm_host_file_paths); +} + +void CdmHostFiles::Initialize( + const base::FilePath& cdm_path, + const std::vector<CdmHostFilePath>& cdm_host_file_paths) { + OpenCdmFile(cdm_path); + OpenCommonFiles(cdm_host_file_paths); +} + +CdmHostFiles::Status CdmHostFiles::InitVerificationWithAdapter( + base::NativeLibrary cdm_adapter_library, + const base::FilePath& cdm_adapter_path) { + DVLOG(1) << __func__; + DCHECK(cdm_adapter_library); + base::NativeLibrary cdm_library = + GetCdmLibrary(cdm_adapter_library, cdm_adapter_path); + if (!cdm_library) + return Status::kCdmLoadFailed; + + return InitVerification(cdm_library); +} + +CdmHostFiles::Status CdmHostFiles::InitVerification( + base::NativeLibrary cdm_library) { + DVLOG(1) << __func__; + DCHECK(cdm_library); + + // Get function pointer exported by the CDM. + // See media/cdm/api/content_decryption_module_ext.h. + using InitVerificationFunc = + bool (*)(const cdm::HostFile* cdm_host_files, uint32_t num_files); + static const char kInitVerificationFuncName[] = "VerifyCdmHost_0"; + + InitVerificationFunc init_verification_func = + reinterpret_cast<InitVerificationFunc>( + base::GetFunctionPointerFromNativeLibrary(cdm_library, + kInitVerificationFuncName)); + if (!init_verification_func) { + LOG(ERROR) << "Function " << kInitVerificationFuncName << " not found."; + CloseAllFiles(); + return Status::kGetFunctionFailed; + } + + // Fills |cdm_host_files| with common and CDM specific files. + std::vector<cdm::HostFile> cdm_host_files; + TakePlatformFiles(&cdm_host_files); + + // std::vector::data() is not guaranteed to be nullptr when empty(). + const cdm::HostFile* cdm_host_files_ptr = + cdm_host_files.empty() ? nullptr : cdm_host_files.data(); + + // Call |init_verification_func| on the CDM with |cdm_host_files|. Note that + // the ownership of these files are transferred to the CDM, which will close + // the files immediately after use. + DVLOG(1) << __func__ << ": Calling " << kInitVerificationFuncName + << "() with " << cdm_host_files.size() << " files."; + for (const auto& host_file : cdm_host_files) { + DVLOG(1) << " - File Path: " << host_file.file_path; + DVLOG(1) << " - File: " << host_file.file; + DVLOG(1) << " - Sig File: " << host_file.sig_file; + } + + if (!init_verification_func(cdm_host_files_ptr, cdm_host_files.size())) { + DVLOG(1) << "Failed to verify CDM host."; + CloseAllFiles(); + return Status::kInitVerificationFailed; + } + + // Close all files not passed to the CDM. + CloseAllFiles(); + return Status::kSuccess; +} + +void CdmHostFiles::CloseAllFiles() { + common_files_.clear(); + cdm_specific_files_.clear(); +} + +void CdmHostFiles::OpenCommonFiles( + const std::vector<CdmHostFilePath>& cdm_host_file_paths) { + DCHECK(common_files_.empty()); + + for (const auto& value : cdm_host_file_paths) { + common_files_.push_back( + CdmHostFile::Create(value.file_path, value.sig_file_path)); + } +} + +void CdmHostFiles::OpenCdmFileWithAdapter( + const base::FilePath& cdm_adapter_path) { + DCHECK(!cdm_adapter_path.empty()); + cdm_specific_files_.push_back( + CdmHostFile::Create(cdm_adapter_path, GetSigFilePath(cdm_adapter_path))); + + base::FilePath cdm_path = GetCdmPath(cdm_adapter_path); + if (cdm_path.empty()) { + LOG(ERROR) << "CDM path is empty."; + return; + } + + OpenCdmFile(cdm_path); +} + +void CdmHostFiles::OpenCdmFile(const base::FilePath& cdm_path) { + DCHECK(!cdm_path.empty()); + cdm_specific_files_.push_back( + CdmHostFile::Create(cdm_path, GetSigFilePath(cdm_path))); +} + +void CdmHostFiles::TakePlatformFiles( + std::vector<cdm::HostFile>* cdm_host_files) { + DCHECK(cdm_host_files->empty()); + + // Populate an array of cdm::HostFile. + for (const auto& file : common_files_) + cdm_host_files->push_back(file->TakePlatformFile()); + for (const auto& file : cdm_specific_files_) + cdm_host_files->push_back(file->TakePlatformFile()); +} + +// Question(xhwang): Any better way to check whether a plugin is a CDM? Maybe +// when we register the plugin we can set some flag explicitly? +bool IsCdm(const base::FilePath& cdm_adapter_path) { + return !GetCdmPath(cdm_adapter_path).empty(); +} + +} // namespace media diff --git a/chromium/media/cdm/cdm_host_files.h b/chromium/media/cdm/cdm_host_files.h new file mode 100644 index 00000000000..012fd421693 --- /dev/null +++ b/chromium/media/cdm/cdm_host_files.h @@ -0,0 +1,105 @@ +// Copyright 2016 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 MEDIA_CDM_CDM_HOST_FILES_H_ +#define MEDIA_CDM_CDM_HOST_FILES_H_ + +#include <memory> +#include <vector> + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "base/native_library.h" +#include "base/path_service.h" +#include "build/build_config.h" +#include "media/base/media_export.h" +#include "media/cdm/api/content_decryption_module_ext.h" +#include "media/cdm/cdm_host_file.h" +#include "media/cdm/cdm_paths.h" + +namespace base { +class FilePath; +} + +namespace media { + +// Manages all CDM host files. + +// TODO(xhwang): Remove all functions suffixed with "WithAdapter" after CDM +// adapter is deprecated. + +class MEDIA_EXPORT CdmHostFiles { + public: + CdmHostFiles(); + ~CdmHostFiles(); + + // Opens all common files and CDM specific files for the CDM adapter + // registered at |cdm_adapter_path|. + void InitializeWithAdapter( + const base::FilePath& cdm_adapter_path, + const std::vector<CdmHostFilePath>& cdm_host_file_paths); + + // Opens all common files and CDM specific files for the CDM at |cdm_path|. + void Initialize(const base::FilePath& cdm_path, + const std::vector<CdmHostFilePath>& cdm_host_file_paths); + + // Status of CDM host verification. + // Note: Reported to UMA. Do not change the values. + enum class Status { + kNotCalled = 0, + kSuccess = 1, + kCdmLoadFailed = 2, + kGetFunctionFailed = 3, + kInitVerificationFailed = 4, + kStatusCount + }; + + // Initializes the verification of CDM files by calling the function exported + // by the CDM. If unexpected error happens, all files will be closed. + // Otherwise, the PlatformFiles are passed to the CDM which will close the + // files later. + // NOTE: Initialize*() must be called before calling this. + Status InitVerificationWithAdapter(base::NativeLibrary cdm_adapter_library, + const base::FilePath& cdm_adapter_path); + Status InitVerification(base::NativeLibrary cdm_library); + + void CloseAllFiles(); + + private: + // Opens common CDM host files shared by all CDMs. + void OpenCommonFiles(const std::vector<CdmHostFilePath>& cdm_host_file_paths); + + // Opens the CDM file and the CDM adapter file. + void OpenCdmFileWithAdapter(const base::FilePath& cdm_adapter_path); + + // Opens the CDM file. + void OpenCdmFile(const base::FilePath& cdm_path); + + // Fills |cdm_host_files| with common and CDM specific files. The ownership + // of those files are also transferred. + void TakePlatformFiles(std::vector<cdm::HostFile>* cdm_host_files); + + using ScopedFileVector = std::vector<std::unique_ptr<CdmHostFile>>; + + // Files common to all CDM types, e.g. main executable. + ScopedFileVector common_files_; + + // Files specific to each CDM type. When the CDM is hosted by a CDM adapter, + // this includes both the CDM adapter and the CDM. Otherwise, this only + // includes the CDM. + ScopedFileVector cdm_specific_files_; + + DISALLOW_COPY_AND_ASSIGN(CdmHostFiles); +}; + +// Returns whether the |cdm_adapter_path| corresponds to a known CDM. +bool MEDIA_EXPORT IsCdm(const base::FilePath& cdm_adapter_path); + +} // namespace media + +#endif // MEDIA_CDM_CDM_HOST_FILES_H_ diff --git a/chromium/media/cdm/cdm_module.cc b/chromium/media/cdm/cdm_module.cc index 28744bcdeb2..150f2e0e825 100644 --- a/chromium/media/cdm/cdm_module.cc +++ b/chromium/media/cdm/cdm_module.cc @@ -4,19 +4,13 @@ #include "media/cdm/cdm_module.h" -#include "base/base_paths.h" #include "base/memory/ptr_util.h" -#include "base/path_service.h" #include "build/build_config.h" -#include "media/base/key_system_names.h" -#include "media/base/key_systems.h" -#include "media/cdm/cdm_paths.h" -#if defined(OS_MACOSX) -#include "base/mac/bundle_locations.h" -#endif - -#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) +#include "base/metrics/histogram_macros.h" +#include "media/cdm/cdm_host_files.h" +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) // INITIALIZE_CDM_MODULE is a macro in api/content_decryption_module.h. // However, we need to pass it as a string to GetFunctionPointer(). The follow @@ -28,50 +22,28 @@ namespace media { namespace { -// TODO(xhwang): We should have the CDM path forwarded from the browser process. -// See http://crbug.com/510604 -base::FilePath GetCdmPath(const std::string& key_system) { - base::FilePath cdm_path; +static CdmModule* g_cdm_module = nullptr; -#if defined(WIDEVINE_CDM_AVAILABLE) - if (key_system == kWidevineKeySystem) { - // Build the library path for the Widevine CDM. - base::FilePath cdm_base_path; +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) +// Initialize CDM host verification. Returns false if fatal error happened. +// Otherwise returns true. +// TODO(xhwang): Add comments on the sandbox model after the CDM process is +// sandboxed. +void InitCdmHostVerification( + base::NativeLibrary cdm_library, + const base::FilePath& cdm_path, + const std::vector<CdmHostFilePath>& cdm_host_file_paths) { + DCHECK(cdm_library); -#if defined(OS_MACOSX) - base::FilePath framework_bundle_path = base::mac::FrameworkBundlePath(); - cdm_base_path = framework_bundle_path.Append("Libraries"); -#else - base::PathService::Get(base::DIR_MODULE, &cdm_base_path); -#endif + CdmHostFiles cdm_host_files; + cdm_host_files.Initialize(cdm_path, cdm_host_file_paths); - cdm_base_path = cdm_base_path.Append( - GetPlatformSpecificDirectory(kWidevineCdmBaseDirectory)); - cdm_path = cdm_base_path.AppendASCII( - base::GetNativeLibraryName(kWidevineCdmLibraryName)); - } -#endif // defined(WIDEVINE_CDM_AVAILABLE) - -// The hard-coded path for ClearKeyCdm does not work on Mac due to bundling. -// See http://crbug.com/736106 -#if !defined(OS_MACOSX) - if (IsExternalClearKey(key_system)) { - DCHECK(cdm_path.empty()); - base::FilePath cdm_base_path; - base::PathService::Get(base::DIR_MODULE, &cdm_base_path); - cdm_base_path = cdm_base_path.Append( - GetPlatformSpecificDirectory(kClearKeyCdmBaseDirectory)); - cdm_path = cdm_base_path.AppendASCII( - base::GetNativeLibraryName(kClearKeyCdmLibraryName)); - } -#endif // !defined(OS_MACOSX) + auto status = cdm_host_files.InitVerification(cdm_library); - DVLOG(1) << __func__ << ": cdm_path = " << cdm_path.value() - << ", key_system = " << key_system; - return cdm_path; + UMA_HISTOGRAM_ENUMERATION("Media.EME.CdmHostVerificationStatus", status, + CdmHostFiles::Status::kStatusCount); } - -static CdmModule* g_cdm_module = nullptr; +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) } // namespace @@ -104,29 +76,28 @@ CdmModule::~CdmModule() { deinitialize_cdm_module_func_(); } -CdmModule::CreateCdmFunc CdmModule::GetCreateCdmFunc( - const std::string& key_system) { - if (!is_initialize_called_) { - Initialize(key_system); - DCHECK(is_initialize_called_); +CdmModule::CreateCdmFunc CdmModule::GetCreateCdmFunc() { + if (!was_initialize_called_) { + NOTREACHED() << __func__ << " called before CdmModule is initialized."; + return nullptr; } + // If initialization failed, nullptr will be returned. return create_cdm_func_; } -void CdmModule::Initialize(const std::string& key_system) { - DVLOG(2) << __func__ << ": key_system = " << key_system; +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) +bool CdmModule::Initialize(const base::FilePath& cdm_path, + std::vector<CdmHostFilePath> cdm_host_file_paths) { +#else +bool CdmModule::Initialize(const base::FilePath& cdm_path) { +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + DVLOG(2) << __func__ << ": cdm_path = " << cdm_path.value(); - DCHECK(!is_initialize_called_); - is_initialize_called_ = true; + DCHECK(!was_initialize_called_); + was_initialize_called_ = true; - // |cdm_path_| could've been set in SetCdmPathForTesting(). - base::FilePath cdm_path = - cdm_path_.empty() ? GetCdmPath(key_system) : cdm_path_; - if (cdm_path.empty()) { - DVLOG(1) << "CDM path for " + key_system + " could not be found."; - return; - } + cdm_path_ = cdm_path; // Load the CDM. // TODO(xhwang): Report CDM load error to UMA. @@ -135,30 +106,50 @@ void CdmModule::Initialize(const std::string& key_system) { if (!library_.is_valid()) { LOG(ERROR) << "CDM at " << cdm_path.value() << " could not be loaded."; LOG(ERROR) << "Error: " << error.ToString(); - return; + return false; } // Get function pointers. // TODO(xhwang): Define function names in macros to avoid typo errors. - using InitializeCdmModuleFunc = void (*)(); - InitializeCdmModuleFunc initialize_cdm_module_func = - reinterpret_cast<InitializeCdmModuleFunc>( - library_.GetFunctionPointer(MAKE_STRING(INITIALIZE_CDM_MODULE))); + initialize_cdm_module_func_ = reinterpret_cast<InitializeCdmModuleFunc>( + library_.GetFunctionPointer(MAKE_STRING(INITIALIZE_CDM_MODULE))); deinitialize_cdm_module_func_ = reinterpret_cast<DeinitializeCdmModuleFunc>( library_.GetFunctionPointer("DeinitializeCdmModule")); create_cdm_func_ = reinterpret_cast<CreateCdmFunc>( library_.GetFunctionPointer("CreateCdmInstance")); - if (!initialize_cdm_module_func || !deinitialize_cdm_module_func_ || + if (!initialize_cdm_module_func_ || !deinitialize_cdm_module_func_ || !create_cdm_func_) { - LOG(ERROR) << "Missing entry function in CDM for " + key_system; + LOG(ERROR) << "Missing entry function in CDM at " << cdm_path.value(); + initialize_cdm_module_func_ = nullptr; deinitialize_cdm_module_func_ = nullptr; create_cdm_func_ = nullptr; library_.Release(); - return; + return false; } - initialize_cdm_module_func(); +#if defined(OS_WIN) + // Load DXVA before sandbox lockdown to give CDM access to Output Protection + // Manager (OPM). + LoadLibraryA("dxva2.dll"); +#endif // defined(OS_WIN) + +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + InitCdmHostVerification(library_.get(), cdm_path_, cdm_host_file_paths); +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + + return true; +} + +void CdmModule::InitializeCdmModule() { + DCHECK(was_initialize_called_); + DCHECK(initialize_cdm_module_func_); + initialize_cdm_module_func_(); +} + +base::FilePath CdmModule::GetCdmPath() const { + DCHECK(was_initialize_called_); + return cdm_path_; } } // namespace media diff --git a/chromium/media/cdm/cdm_module.h b/chromium/media/cdm/cdm_module.h index aa6c5361d8a..d4d607693c7 100644 --- a/chromium/media/cdm/cdm_module.h +++ b/chromium/media/cdm/cdm_module.h @@ -5,11 +5,20 @@ #ifndef MEDIA_CDM_CDM_MODULE_H_ #define MEDIA_CDM_CDM_MODULE_H_ +#include <memory> +#include <vector> + #include "base/files/file_path.h" #include "base/macros.h" #include "base/scoped_native_library.h" #include "media/base/media_export.h" #include "media/cdm/api/content_decryption_module.h" +#include "media/media_features.h" + +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) +#include "media/cdm/cdm_host_file.h" +#include "media/cdm/cdm_host_files.h" +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) namespace media { @@ -28,26 +37,36 @@ class MEDIA_EXPORT CdmModule { GetCdmHostFunc get_cdm_host_func, void* user_data); - CreateCdmFunc GetCreateCdmFunc(const std::string& key_system); + CreateCdmFunc GetCreateCdmFunc(); + +// Loads the CDM, initialize function pointers and initialize the CDM module. +// This must only be called only once. +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) + bool Initialize(const base::FilePath& cdm_path, + std::vector<CdmHostFilePath> cdm_host_file_paths); +#else + bool Initialize(const base::FilePath& cdm_path); +#endif // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) - void SetCdmPathForTesting(const base::FilePath& cdm_path) { - cdm_path_ = cdm_path; - } + // Calls INITIALIZE_CDM_MODULE on the actually library CDM. Must be called + // within the sandbox! + void InitializeCdmModule(); + + base::FilePath GetCdmPath() const; + + bool was_initialize_called() const { return was_initialize_called_; } private: + using InitializeCdmModuleFunc = void (*)(); using DeinitializeCdmModuleFunc = void (*)(); CdmModule(); - // Loads the CDM, initialize function pointers and initialize the CDM module. - // This should only be called once. - // TODO(xhwang): Replace the |key_system| with the path to the CDM. - void Initialize(const std::string& key_system); - - bool is_initialize_called_ = false; + bool was_initialize_called_ = false; base::FilePath cdm_path_; base::ScopedNativeLibrary library_; CreateCdmFunc create_cdm_func_ = nullptr; + InitializeCdmModuleFunc initialize_cdm_module_func_ = nullptr; DeinitializeCdmModuleFunc deinitialize_cdm_module_func_ = nullptr; DISALLOW_COPY_AND_ASSIGN(CdmModule); diff --git a/chromium/media/cdm/cdm_paths.cc b/chromium/media/cdm/cdm_paths.cc index d8eeb7fbd17..4c772ef5dda 100644 --- a/chromium/media/cdm/cdm_paths.cc +++ b/chromium/media/cdm/cdm_paths.cc @@ -25,9 +25,14 @@ const char kClearKeyCdmAdapterFileName[] = #endif const char kClearKeyCdmDisplayName[] = "Clear Key CDM"; - +const char kClearKeyCdmGuid[] = "C1A6B4E3-FE48-4D53-9F52-244AEEAD5335"; +const char kClearKeyCdmDifferentGuid[] = "747C565D-34EE-4B0D-AC1E-4F9FB17DDB40"; const char kClearKeyCdmPepperMimeType[] = "application/x-ppapi-clearkey-cdm"; +// As the file system was initially used by the CDM running as a pepper plugin, +// this ID is based on the pepper plugin MIME type. +const char kClearKeyCdmFileSystemId[] = "application_x-ppapi-clearkey-cdm"; + // Note: This file must be in sync with cdm_paths.gni. // TODO(xhwang): Improve how we enable platform specific path. See // http://crbug.com/468584 diff --git a/chromium/media/cdm/cdm_paths.h b/chromium/media/cdm/cdm_paths.h index 755006030a4..0ecf0fdad25 100644 --- a/chromium/media/cdm/cdm_paths.h +++ b/chromium/media/cdm/cdm_paths.h @@ -22,10 +22,21 @@ extern const char kClearKeyCdmAdapterFileName[]; // Display name for Clear Key CDM. extern const char kClearKeyCdmDisplayName[]; +// The default GUID for Clear Key Cdm. +extern const char kClearKeyCdmGuid[]; + +// A different GUID for Clear Key Cdm for testing running different types of +// CDMs in the system. +extern const char kClearKeyCdmDifferentGuid[]; + // Pepper type for Clear Key CDM. // TODO(xhwang): Remove after switching to mojo CDM. extern const char kClearKeyCdmPepperMimeType[]; +// Identifier used by the PluginPrivateFileSystem to identify the files stored +// for the Clear Key CDM. +extern const char kClearKeyCdmFileSystemId[]; + // Returns the path of a CDM relative to DIR_COMPONENTS. // On platforms where a platform specific path is used, returns // |cdm_base_path|/_platform_specific/<platform>_<arch> diff --git a/chromium/media/cdm/cdm_wrapper.h b/chromium/media/cdm/cdm_wrapper.h index cf6851b70ff..2e54872eda2 100644 --- a/chromium/media/cdm/cdm_wrapper.h +++ b/chromium/media/cdm/cdm_wrapper.h @@ -136,7 +136,8 @@ class CdmWrapper { cdm::QueryResult result, uint32_t link_mask, uint32_t output_protection_mask) = 0; - virtual void OnStorageId(const uint8_t* storage_id, + virtual void OnStorageId(uint32_t version, + const uint8_t* storage_id, uint32_t storage_id_size) = 0; protected: @@ -275,8 +276,10 @@ class CdmWrapperImpl : public CdmWrapper { output_protection_mask); } - void OnStorageId(const uint8_t* storage_id, uint32_t storage_id_size) { - cdm_->OnStorageId(storage_id, storage_id_size); + void OnStorageId(uint32_t version, + const uint8_t* storage_id, + uint32_t storage_id_size) { + cdm_->OnStorageId(version, storage_id, storage_id_size); } private: @@ -300,6 +303,7 @@ bool CdmWrapperImpl<cdm::ContentDecryptionModule_8>::GetStatusForPolicy( template <> void CdmWrapperImpl<cdm::ContentDecryptionModule_8>::OnStorageId( + uint32_t version, const uint8_t* storage_id, uint32_t storage_id_size) {} diff --git a/chromium/media/cdm/json_web_key.cc b/chromium/media/cdm/json_web_key.cc index 7431b8d41a9..3a5fab110c5 100644 --- a/chromium/media/cdm/json_web_key.cc +++ b/chromium/media/cdm/json_web_key.cc @@ -174,7 +174,7 @@ bool ExtractKeysFromJWKSet(const std::string& jwk_set, } std::unique_ptr<base::Value> root(base::JSONReader().ReadToValue(jwk_set)); - if (!root.get() || root->GetType() != base::Value::Type::DICTIONARY) { + if (!root.get() || root->type() != base::Value::Type::DICTIONARY) { DVLOG(1) << "Not valid JSON: " << jwk_set << ", root: " << root.get(); return false; } @@ -243,7 +243,7 @@ bool ExtractKeyIdsFromKeyIdsInitData(const std::string& input, } std::unique_ptr<base::Value> root(base::JSONReader().ReadToValue(input)); - if (!root.get() || root->GetType() != base::Value::Type::DICTIONARY) { + if (!root.get() || root->type() != base::Value::Type::DICTIONARY) { error_message->assign("Not valid JSON: "); error_message->append(ShortenTo64Characters(input)); return false; @@ -377,7 +377,7 @@ bool ExtractFirstKeyIdFromLicenseRequest(const std::vector<uint8_t>& license, std::unique_ptr<base::Value> root( base::JSONReader().ReadToValue(license_as_str)); - if (!root.get() || root->GetType() != base::Value::Type::DICTIONARY) { + if (!root.get() || root->type() != base::Value::Type::DICTIONARY) { DVLOG(1) << "Not valid JSON: " << license_as_str; return false; } diff --git a/chromium/media/cdm/mock_helpers.cc b/chromium/media/cdm/mock_helpers.cc index 99625e5e0fc..64c165f7ce7 100644 --- a/chromium/media/cdm/mock_helpers.cc +++ b/chromium/media/cdm/mock_helpers.cc @@ -36,8 +36,9 @@ void MockCdmAuxiliaryHelper::ChallengePlatform(const std::string& service_id, "", ""); } -void MockCdmAuxiliaryHelper::GetStorageId(StorageIdCB callback) { - std::move(callback).Run(GetStorageIdCalled()); +void MockCdmAuxiliaryHelper::GetStorageId(uint32_t version, + StorageIdCB callback) { + std::move(callback).Run(version, GetStorageIdCalled(version)); } } // namespace media diff --git a/chromium/media/cdm/mock_helpers.h b/chromium/media/cdm/mock_helpers.h index a6868f9da4e..82141e1ea97 100644 --- a/chromium/media/cdm/mock_helpers.h +++ b/chromium/media/cdm/mock_helpers.h @@ -46,8 +46,8 @@ class MockCdmAuxiliaryHelper : public CdmAuxiliaryHelper { const std::string& challenge, ChallengePlatformCB callback) override; - MOCK_METHOD0(GetStorageIdCalled, std::vector<uint8_t>()); - void GetStorageId(StorageIdCB callback) override; + MOCK_METHOD1(GetStorageIdCalled, std::vector<uint8_t>(uint32_t version)); + void GetStorageId(uint32_t version, StorageIdCB callback) override; private: std::unique_ptr<CdmAllocator> allocator_; diff --git a/chromium/media/cdm/platform_verification.h b/chromium/media/cdm/platform_verification.h index f56e2a9db1a..83b039dd782 100644 --- a/chromium/media/cdm/platform_verification.h +++ b/chromium/media/cdm/platform_verification.h @@ -25,7 +25,8 @@ class MEDIA_EXPORT PlatformVerification { const std::string& signed_data_signature, const std::string& platform_key_certificate)>; using StorageIdCB = - base::OnceCallback<void(const std::vector<uint8_t>& storage_id)>; + base::OnceCallback<void(uint32_t version, + const std::vector<uint8_t>& storage_id)>; // Allows authorized services to verify that the underlying platform is // trusted. An example of a trusted platform is a Chrome OS device in @@ -43,11 +44,14 @@ class MEDIA_EXPORT PlatformVerification { const std::string& challenge, ChallengePlatformCB callback) = 0; - // Requests the device's Storage Id. |callback| will be called with the - // following value: - // - |storage_id|: The devices Storage Id. It may be the empty string if it - // is not supported by the platform. - virtual void GetStorageId(StorageIdCB callback) = 0; + // Requests a specific version of the device's Storage Id. If |version| = 0, + // the latest available version will be returned. |callback| will be called + // with the following values: + // - |version|: The version of the device's Storage Id being requested. + // - |storage_id|: The device's Storage Id. It may be empty if Storage Id + // is not supported by the platform, or if the requested + // version does not exist. + virtual void GetStorageId(uint32_t version, StorageIdCB callback) = 0; private: DISALLOW_COPY_AND_ASSIGN(PlatformVerification); diff --git a/chromium/media/cdm/ppapi/cdm_file_io_test.h b/chromium/media/cdm/ppapi/cdm_file_io_test.h index 25367334c50..37d8fc70444 100644 --- a/chromium/media/cdm/ppapi/cdm_file_io_test.h +++ b/chromium/media/cdm/ppapi/cdm_file_io_test.h @@ -9,12 +9,12 @@ #include <stdint.h> #include <list> -#include <stack> #include <string> #include <vector> #include "base/callback.h" #include "base/compiler_specific.h" +#include "base/containers/stack.h" #include "base/macros.h" #include "media/cdm/api/content_decryption_module.h" @@ -132,7 +132,7 @@ class FileIOTest : public cdm::FileIOClient { // so that we can test multiple cdm::FileIO objects accessing the same file. // In the current implementation, all ACTION_* are performed on the latest // opened cdm::FileIO object, hence the stack. - std::stack<cdm::FileIO*> file_io_stack_; + base::stack<cdm::FileIO*> file_io_stack_; }; // Tests cdm::FileIO implementation. diff --git a/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc index 2ef815d0ceb..0fa4fe70d50 100644 --- a/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc +++ b/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc @@ -70,6 +70,8 @@ const char kExternalClearKeyVerifyCdmHostTestKeySystem[] = "org.chromium.externalclearkey.verifycdmhosttest"; const char kExternalClearKeyStorageIdTestKeySystem[] = "org.chromium.externalclearkey.storageidtest"; +const char kExternalClearKeyDifferentGuidTestKeySystem[] = + "org.chromium.externalclearkey.differentguid"; const int64_t kSecondsPerMinute = 60; const int64_t kMsPerSecond = 1000; @@ -256,7 +258,8 @@ void* CreateCdmInstance(int cdm_interface_version, key_system_string != kExternalClearKeyPlatformVerificationTestKeySystem && key_system_string != kExternalClearKeyCrashKeySystem && key_system_string != kExternalClearKeyVerifyCdmHostTestKeySystem && - key_system_string != kExternalClearKeyStorageIdTestKeySystem) { + key_system_string != kExternalClearKeyStorageIdTestKeySystem && + key_system_string != kExternalClearKeyDifferentGuidTestKeySystem) { DVLOG(1) << "Unsupported key system:" << key_system_string; return nullptr; } @@ -283,13 +286,13 @@ static bool g_verify_host_files_result = false; bool VerifyCdmHost_0(const cdm::HostFile* host_files, uint32_t num_files) { DVLOG(1) << __func__ << ": " << num_files; - // We should always have the CDM and CDM adapter and at least one common file. + // We should always have the CDM and at least one common file. // The common CDM host file (e.g. chrome) might not exist since we are running // in browser_tests. - const uint32_t kMinNumHostFiles = 3; + const uint32_t kMinNumHostFiles = 2; - // We should always have the CDM and CDM adapter. - const int kNumCdmFiles = 2; + // We should always have the CDM. + const int kNumCdmFiles = 1; if (num_files < kMinNumHostFiles) { LOG(ERROR) << "Too few host files: " << num_files; @@ -693,7 +696,7 @@ cdm::Status ClearKeyCdm::DecryptAndDecodeSamples( // that the session is properly closed. if (!last_session_id_.empty() && key_system_ == kExternalClearKeyCrashKeySystem) { - CHECK(false); + CHECK(false) << "Crash in decrypt-and-decode with crash key system."; } scoped_refptr<media::DecoderBuffer> buffer; @@ -822,7 +825,8 @@ void ClearKeyCdm::OnQueryOutputProtectionStatus( OnUnitTestComplete(true); }; -void ClearKeyCdm::OnStorageId(const uint8_t* storage_id, +void ClearKeyCdm::OnStorageId(uint32_t version, + const uint8_t* storage_id, uint32_t storage_id_size) { if (!is_running_storage_id_test_) { NOTREACHED() << "OnStorageId() called unexpectedly."; @@ -856,6 +860,13 @@ void ClearKeyCdm::OnSessionKeysChange(const std::string& session_id, CdmKeysInfo keys_info) { DVLOG(1) << __func__ << ": size = " << keys_info.size(); + // Crash if the special key ID "crash" is present. + const std::vector<uint8_t> kCrashKeyId{'c', 'r', 'a', 's', 'h'}; + for (const auto& key_info : keys_info) { + if (key_info->key_id == kCrashKeyId) + CHECK(false) << "Crash on special crash key ID."; + } + std::vector<cdm::KeyInformation> keys_vector; ConvertCdmKeysInfo(keys_info, &keys_vector); host_->OnSessionKeysChange(session_id.data(), session_id.length(), @@ -1006,7 +1017,9 @@ void ClearKeyCdm::VerifyCdmHostTest() { void ClearKeyCdm::StartStorageIdTest() { DVLOG(1) << __func__; is_running_storage_id_test_ = true; - host_->RequestStorageId(); + + // Request the latest available version. + host_->RequestStorageId(0); } } // namespace media diff --git a/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.h index db989cc227c..59e8603973c 100644 --- a/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.h +++ b/chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.h @@ -85,7 +85,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface { void OnQueryOutputProtectionStatus(cdm::QueryResult result, uint32_t link_mask, uint32_t output_protection_mask) override; - void OnStorageId(const uint8_t* storage_id, + void OnStorageId(uint32_t version, + const uint8_t* storage_id, uint32_t storage_id_size) override; private: diff --git a/chromium/media/cdm/ppapi/ppapi_cdm_adapter.cc b/chromium/media/cdm/ppapi/ppapi_cdm_adapter.cc index f7601903b2a..960277f2fc9 100644 --- a/chromium/media/cdm/ppapi/ppapi_cdm_adapter.cc +++ b/chromium/media/cdm/ppapi/ppapi_cdm_adapter.cc @@ -28,6 +28,11 @@ const uint32_t kSizeKBMin = 1; const uint32_t kSizeKBMax = 512 * 1024; // 512MB const uint32_t kSizeKBBuckets = 100; +// Only support version 1 of Storage Id. However, the "latest" version can also +// be requested. +const uint32_t kRequestLatestStorageIdVersion = 0; +const uint32_t kCurrentStorageIdVersion = 1; + #if !defined(NDEBUG) #define DLOG_TO_CONSOLE(message) LogToConsole(message); #else @@ -1203,11 +1208,12 @@ void PpapiCdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type, } } -void PpapiCdmAdapter::RequestStorageId() { - CDM_DLOG() << __func__; - +void PpapiCdmAdapter::RequestStorageId(uint32_t version) { // If persistent storage is not allowed, no need to get the Storage ID. - if (allow_persistent_state_) { + // As well, only allow the request if the current version (or "latest") + // is requested. + if (allow_persistent_state_ && (version == kCurrentStorageIdVersion || + version == kRequestLatestStorageIdVersion)) { linked_ptr<pp::Var> response(new pp::Var()); int32_t result = platform_verification_.GetStorageId( response.get(), callback_factory_.NewCallback( @@ -1219,7 +1225,7 @@ void PpapiCdmAdapter::RequestStorageId() { PP_DCHECK(result != PP_OK); } - cdm_->OnStorageId(nullptr, 0); + cdm_->OnStorageId(version, nullptr, 0); } // The CDM owns the returned object and must call FileIO::Close() to release it. @@ -1339,16 +1345,21 @@ void PpapiCdmAdapter::QueryOutputProtectionStatusDone(int32_t result) { void PpapiCdmAdapter::RequestStorageIdDone( int32_t result, const linked_ptr<pp::Var>& response) { - std::string storage_id; - - if (result == PP_OK) - storage_id = response->AsString(); + uint8_t* storage_id_ptr; + uint32_t storage_id_size; - CDM_DLOG() << __func__ << ": result = " << result - << ", storage_id = " << storage_id; + if (result == PP_OK && response->is_array_buffer()) { + pp::VarArrayBuffer storage_id(*response); + storage_id_ptr = static_cast<uint8_t*>(storage_id.Map()); + storage_id_size = storage_id.ByteLength(); + } else { + CDM_DLOG() << __func__ << " failed, result = " << result; + storage_id_ptr = nullptr; + storage_id_size = 0; + } - cdm_->OnStorageId(reinterpret_cast<const uint8_t*>(storage_id.data()), - static_cast<uint32_t>(storage_id.length())); + // Pepper only supports a single version of Storage ID. + cdm_->OnStorageId(kCurrentStorageIdVersion, storage_id_ptr, storage_id_size); } PpapiCdmAdapter::SessionError::SessionError( diff --git a/chromium/media/cdm/ppapi/ppapi_cdm_adapter.h b/chromium/media/cdm/ppapi/ppapi_cdm_adapter.h index f97cf9b69ee..75e80d81f30 100644 --- a/chromium/media/cdm/ppapi/ppapi_cdm_adapter.h +++ b/chromium/media/cdm/ppapi/ppapi_cdm_adapter.h @@ -123,7 +123,7 @@ class PpapiCdmAdapter : public pp::Instance, void QueryOutputProtectionStatus() override; void OnDeferredInitializationDone(cdm::StreamType stream_type, cdm::Status decoder_status) override; - void RequestStorageId() override; + void RequestStorageId(uint32_t version) override; cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) override; // cdm::Host_8 implementation (differences from Host_9). |