summaryrefslogtreecommitdiff
path: root/chromium/media/cdm
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 15:06:40 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:48:58 +0000
commitdaa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch)
tree96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/media/cdm
parentbe59a35641616a4cf23c4a13fa0632624b021c1b (diff)
downloadqtwebengine-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')
-rw-r--r--chromium/media/cdm/BUILD.gn19
-rw-r--r--chromium/media/cdm/aes_decryptor_unittest.cc9
-rw-r--r--chromium/media/cdm/api/codereview.settings12
-rw-r--r--chromium/media/cdm/api/content_decryption_module.h44
-rw-r--r--chromium/media/cdm/cdm_adapter.cc27
-rw-r--r--chromium/media/cdm/cdm_adapter.h5
-rw-r--r--chromium/media/cdm/cdm_adapter_unittest.cc16
-rw-r--r--chromium/media/cdm/cdm_auxiliary_helper.cc4
-rw-r--r--chromium/media/cdm/cdm_auxiliary_helper.h2
-rw-r--r--chromium/media/cdm/cdm_host_file.cc57
-rw-r--r--chromium/media/cdm/cdm_host_file.h66
-rw-r--r--chromium/media/cdm/cdm_host_files.cc240
-rw-r--r--chromium/media/cdm/cdm_host_files.h105
-rw-r--r--chromium/media/cdm/cdm_module.cc139
-rw-r--r--chromium/media/cdm/cdm_module.h39
-rw-r--r--chromium/media/cdm/cdm_paths.cc7
-rw-r--r--chromium/media/cdm/cdm_paths.h11
-rw-r--r--chromium/media/cdm/cdm_wrapper.h10
-rw-r--r--chromium/media/cdm/json_web_key.cc6
-rw-r--r--chromium/media/cdm/mock_helpers.cc5
-rw-r--r--chromium/media/cdm/mock_helpers.h4
-rw-r--r--chromium/media/cdm/platform_verification.h16
-rw-r--r--chromium/media/cdm/ppapi/cdm_file_io_test.h4
-rw-r--r--chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc29
-rw-r--r--chromium/media/cdm/ppapi/external_clear_key/clear_key_cdm.h3
-rw-r--r--chromium/media/cdm/ppapi/ppapi_cdm_adapter.cc37
-rw-r--r--chromium/media/cdm/ppapi/ppapi_cdm_adapter.h2
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).