Source release 18.5.0

This commit is contained in:
Matt Feddersen
2024-03-28 19:15:22 -07:00
parent b2c35151ad
commit 28ec8548c6
109 changed files with 3623 additions and 1012 deletions

View File

@@ -15,6 +15,7 @@
'variables': {
'has_dual_key%': 'false',
'embedded_cert%': '',
'support_embedded_cert_functions%': 'false',
},
'targets': [
{
@@ -23,12 +24,20 @@
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'includes': ['../third_party/protoc.gypi'],
'includes': ['../third_party/disable_warnings.gypi'],
'dependencies': [ '<(proto_gen_gyp_path):generate_license_protocol' ],
'sources': [
'../core/src/license_protocol.proto',
'<(proto_cc_dir)/license_protocol.pb.cc'
],
'variables': {
'proto_in_dir': '../core/src',
'include_dirs': [
'<(proto_cc_dir)',
'<(DEPTH)/third_party/protobuf/src'
],
'direct_dependent_settings': {
'include_dirs': [
'<(proto_cc_dir)',
'<(DEPTH)/third_party/protobuf/src'
]
},
},
{
@@ -37,10 +46,20 @@
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'includes': ['../third_party/protoc.gypi'],
'sources': ['../core/src/device_files.proto',],
'variables': {
'proto_in_dir': '../core/src',
'includes': ['../third_party/disable_warnings.gypi'],
'dependencies': [ '<(proto_gen_gyp_path):generate_device_files' ],
'sources': [
'<(proto_cc_dir)/device_files.pb.cc'
],
'include_dirs': [
'<(proto_cc_dir)',
'<(DEPTH)/third_party/protobuf/src'
],
'direct_dependent_settings': {
'include_dirs': [
'<(proto_cc_dir)',
'<(DEPTH)/third_party/protobuf/src'
]
},
},
{
@@ -49,10 +68,20 @@
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'includes': ['../third_party/protoc.gypi'],
'sources': ['../metrics/src/wv_metrics.proto',],
'variables': {
'proto_in_dir': '../metrics/src',
'includes': ['../third_party/disable_warnings.gypi'],
'dependencies': [ '<(proto_gen_gyp_path):generate_metrics_proto' ],
'sources': [
'<(proto_cc_dir)/wv_metrics.pb.cc'
],
'include_dirs': [
'<(proto_cc_dir)',
'<(DEPTH)/third_party/protobuf/src'
],
'direct_dependent_settings': {
'include_dirs': [
'<(proto_cc_dir)',
'<(DEPTH)/third_party/protobuf/src'
]
},
},
{
@@ -178,6 +207,11 @@
'../core/src/oemcrypto_ota_stubs.cpp',
],
}],
['support_embedded_cert_functions=="false"', {
'sources': [
'../core/src/oemcrypto_embedded_cert_stubs.cpp',
],
}],
],
}, # widevine_cdm_core target
{

View File

@@ -126,8 +126,10 @@
'../core/test/license_request.cpp',
'../core/test/url_request.cpp',
'../util/src/string_conversions.cpp',
'../util/src/string_format.cpp',
'../util/test/test_sleep.cpp',
'src/log.cpp',
'src/logger_global.cpp',
'test/perf_test.cpp',
'test/perf_test_dynamic.cpp',
'test/test_host.cpp',
@@ -136,6 +138,7 @@
'include_dirs': [
'../core/include',
'../core/test',
'../oemcrypto/include',
'../util/include',
'../util/test',
'include',

View File

@@ -11,7 +11,9 @@
'../core/test/cdm_engine_metrics_decorator_unittest.cpp',
'../core/test/cdm_session_unittest.cpp',
'../core/test/cdm_usage_table_unittest.cpp',
'../core/test/core_integration_test.cpp',
'../core/test/config_test_env.cpp',
'../core/test/core_integration_test.cpp',
'../core/test/certificate_provisioning_unittest.cpp',
'../core/test/crypto_session_unittest.cpp',
'../core/test/device_files_unittest.cpp',

View File

@@ -137,11 +137,16 @@ class CDM_EXPORT Cdm : public ITimerClient {
// For ease of comparison, these values are kept in ascending order by version
// number.
enum HdcpVersion : int32_t {
kHdcp1_x = 0,
kHdcp2_0 = 1,
kHdcp2_1 = 2,
kHdcp2_2 = 3,
kHdcp2_3 = 4,
kHdcp1_x = 0, // Any 1.x version
kHdcp1_0 = 100,
kHdcp1_1 = 101,
kHdcp1_2 = 102,
kHdcp1_3 = 103,
kHdcp1_4 = 104,
kHdcp2_0 = 200,
kHdcp2_1 = 201,
kHdcp2_2 = 202,
kHdcp2_3 = 203
};
// Permissible usages for a key. Returned as a set of flags; multiple

View File

@@ -10,7 +10,7 @@
# define CDM_VERSION_MAJOR 18
#endif
#ifndef CDM_VERSION_MINOR
# define CDM_VERSION_MINOR 1
# define CDM_VERSION_MINOR 5
#endif
#ifndef CDM_VERSION_PATCH
# define CDM_VERSION_PATCH 0

View File

@@ -193,5 +193,26 @@
'protoc_bin%': '',
'protobuf_lib_path%': '',
'protoc_host_path%': '',
# Protobuf Generation and Build configurations:
#
# These options allow for different build steps to be specified for proto
# cc file generation than the default step. This can be used to customize
# cc file generation or add additional cc file processing steps before
# proto cc files are built.
#
# The directory where proto cc files that will be compiled are located.
'proto_cc_dir%': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
# The directory where proto cc files generated from proto files will be
# located.
'proto_gen_dir%': '<(SHARED_INTERMEDIATE_DIR)/protoc_out',
# Path to the GYP file that contains the proto cc file generation targets.
# This file must provide the following targets:
# - generate_license_protocol
# - generate_device_files
# - generate_metrics_proto
'proto_gen_gyp_path%': '<(DEPTH)/third_party/generate_proto_cc.gyp',
}, # variables
}

View File

@@ -36,11 +36,6 @@
#include "cdm_version.h"
#include "properties_ce.h"
#ifdef HAS_EMBEDDED_CERT
extern uint8_t kDeviceCert[];
extern size_t kDeviceCertSize;
#endif
namespace widevine {
#ifdef HAS_EMBEDDED_CERT
@@ -151,6 +146,8 @@ class ReadOnlyStorage final : public Cdm::IStorage {
// TODO(b/148693106): Once we have resolved the bugs causing the CDM to
// erroneously write to read-only files, change this to an error instead of
// a silent failure.
(void)name;
(void)data;
return true;
}
@@ -162,6 +159,7 @@ class ReadOnlyStorage final : public Cdm::IStorage {
// TODO(b/148693106): Once we have resolved the bugs causing the CDM to
// erroneously write to read-only files, change this to an error instead of
// a silent failure.
(void)name;
return true;
}
@@ -576,7 +574,21 @@ Cdm::Status CdmImpl::getStatusForHdcpVersion(Cdm::HdcpVersion hdcp,
result = ConvertHdcpLevel(query_value, &max_hdcp);
if (result != kSuccess) return result;
*key_status = (hdcp <= max_hdcp ? Cdm::kUsable : Cdm::kOutputRestricted);
if (hdcp == kHdcp1_x && max_hdcp == kHdcp1_x) {
// Legacy case.
*key_status = Cdm::kUsable;
} else if (hdcp == kHdcp1_x &&
(max_hdcp >= kHdcp1_0 && max_hdcp <= kHdcp1_4)) {
// CDM app is using legacy 1.x value, but OEMCrypto is using newer
// value. Assume usable.
*key_status = Cdm::kUsable;
} else if (max_hdcp == kHdcp1_x && (hdcp >= kHdcp1_0 && hdcp <= kHdcp1_4)) {
// CDM app is using new 1.x value, but OEMCrypto is using legacy
// value. Assume usable.
*key_status = Cdm::kUsable;
} else {
*key_status = (hdcp <= max_hdcp ? Cdm::kUsable : Cdm::kOutputRestricted);
}
}
return kSuccess;
}
@@ -1355,8 +1367,19 @@ CdmSigningAlgorithm CdmImpl::ConvertSigningAlgorithm(
Cdm::Status CdmImpl::ConvertHdcpLevel(const std::string& query_value,
Cdm::HdcpVersion* result) {
if (query_value == QUERY_VALUE_HDCP_V1) {
if (query_value == QUERY_VALUE_HDCP_V1_X) {
// Generic HDCP level
*result = kHdcp1_x;
} else if (query_value == QUERY_VALUE_HDCP_V1_0) {
*result = kHdcp1_0;
} else if (query_value == QUERY_VALUE_HDCP_V1_1) {
*result = kHdcp1_1;
} else if (query_value == QUERY_VALUE_HDCP_V1_2) {
*result = kHdcp1_2;
} else if (query_value == QUERY_VALUE_HDCP_V1_3) {
*result = kHdcp1_3;
} else if (query_value == QUERY_VALUE_HDCP_V1_4) {
*result = kHdcp1_4;
} else if (query_value == QUERY_VALUE_HDCP_V2_0) {
*result = kHdcp2_0;
} else if (query_value == QUERY_VALUE_HDCP_V2_1) {

View File

@@ -34,10 +34,8 @@ namespace {
constexpr char kGlobalDumpFileName[] = "dumped_global_filesystem.dat";
constexpr char kPerOriginDumpFileName[] = "dumped_per_origin_filesystem.dat";
using StorageMap = TestHost::Storage::StorageMap;
// Load a TestHost file system from the real file system.
bool ReloadFileSystem(const char* file_name, StorageMap* map) {
bool ReloadFileSystem(const char* file_name, TestHost::Storage* store) {
std::ifstream input(file_name);
if (input.fail()) {
// This is OK for first pass, but an error for later passes.
@@ -46,7 +44,7 @@ bool ReloadFileSystem(const char* file_name, StorageMap* map) {
}
std::string dumped_file_system((std::istreambuf_iterator<char>(input)),
std::istreambuf_iterator<char>());
if (!wvcdm::RebootTest::ParseDump(dumped_file_system, map)) {
if (!store->LoadFromString(dumped_file_system)) {
LOGE("Could not parse %s", file_name);
return false;
}
@@ -54,31 +52,26 @@ bool ReloadFileSystem(const char* file_name, StorageMap* map) {
}
bool ReloadFileSystems() {
StorageMap global_map;
StorageMap per_origin_map;
if (!ReloadFileSystem(kGlobalDumpFileName, &global_map) ||
!ReloadFileSystem(kPerOriginDumpFileName, &per_origin_map)) {
return false;
}
g_host->global_storage().ResetFiles(global_map);
g_host->per_origin_storage().ResetFiles(per_origin_map);
return true;
return ReloadFileSystem(kGlobalDumpFileName, &g_host->global_storage()) &&
ReloadFileSystem(kPerOriginDumpFileName,
&g_host->per_origin_storage());
}
// Dump a TestHost file system to the real file system. If the dump file
// cannot be written, this raises an exception and crashes the program. Since
// we usually build with exceptions turned off, what this means is that the test
// executable will halt if the file cannot be written.
void DumpFileSystem(const char* file_name, const StorageMap& map) {
std::string dump = wvcdm::RebootTest::DumpData(map);
void DumpFileSystem(const char* file_name, const TestHost::Storage& store) {
std::string dump;
(void)store.SaveToString(&dump);
std::ofstream output(file_name);
output << dump;
output.close();
}
void DumpFileSystems() {
DumpFileSystem(kGlobalDumpFileName, g_host->global_storage().files());
DumpFileSystem(kPerOriginDumpFileName, g_host->per_origin_storage().files());
DumpFileSystem(kGlobalDumpFileName, g_host->global_storage());
DumpFileSystem(kPerOriginDumpFileName, g_host->per_origin_storage());
}
} // namespace

View File

@@ -235,6 +235,15 @@ class CdmTest : public WvCdmTestBase, public Cdm::IEventListener {
protected:
void SetUp() override {
// TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented.
// Many of these tests call EnsureProvisioned which tries to provision the
// test device using a provisioning server. Until support is added for Drm
// Reprovisioning on the server, skip these tests to avoid test failures.
if (wvoec::global_features.provisioning_method ==
OEMCrypto_DrmReprovisioning) {
GTEST_SKIP()
<< "Skipping until Drm Reprovisioning server support is implemented.";
}
WvCdmTestBase::SetUp();
// Clear anything stored, load default device cert.
@@ -1462,6 +1471,12 @@ TEST_F(CdmTest, GetExpiration) {
TEST_P(CdmTestWithRemoveParam, Remove) {
const bool intermediate_close = GetParam();
// TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented.
if (wvoec::global_features.provisioning_method ==
OEMCrypto_DrmReprovisioning) {
GTEST_SKIP()
<< "Skipping until Drm Reprovisioning server support is implemented.";
}
EnsureProvisioned();
std::string session_id;
ASSERT_NO_FATAL_FAILURE(
@@ -1916,27 +1931,22 @@ TEST_F(CdmTest, GetStatusForHdcpResolution) {
// Unfortunately, since we cannot mock the HDCP state, we cannot validate
// the validity of the values returned here, only that meaningful values are
// returned.
Cdm::KeyStatus key_status;
const std::vector<Cdm::HdcpVersion> kSupportedHdcpVersions = {
// Legacy 1.x version
Cdm::kHdcp1_x,
// v17 1.x versions
Cdm::kHdcp1_0, Cdm::kHdcp1_1, Cdm::kHdcp1_2, Cdm::kHdcp1_3, Cdm::kHdcp1_4,
// 2.x versions.
Cdm::kHdcp2_0, Cdm::kHdcp2_1, Cdm::kHdcp2_2, Cdm::kHdcp2_3};
ASSERT_EQ(Cdm::kSuccess,
cdm_->getStatusForHdcpVersion(Cdm::kHdcp1_x, &key_status));
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
ASSERT_EQ(Cdm::kSuccess,
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_0, &key_status));
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
ASSERT_EQ(Cdm::kSuccess,
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_1, &key_status));
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
ASSERT_EQ(Cdm::kSuccess,
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_2, &key_status));
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
ASSERT_EQ(Cdm::kSuccess,
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_3, &key_status));
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
for (const auto version : kSupportedHdcpVersions) {
Cdm::KeyStatus key_status;
ASSERT_EQ(Cdm::kSuccess,
cdm_->getStatusForHdcpVersion(version, &key_status))
<< "HDCP version: " << static_cast<int>(version);
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted))
<< "HDCP version: " << static_cast<int>(version);
}
}
TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
@@ -2162,6 +2172,12 @@ TEST_F(CdmTest, GetMetrics) {
}
TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
// TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented.
if (wvoec::global_features.provisioning_method ==
OEMCrypto_DrmReprovisioning) {
GTEST_SKIP()
<< "Skipping until Drm Reprovisioning server support is implemented.";
}
EnsureProvisioned();
DecryptParam param = GetParam();

View File

@@ -20,6 +20,7 @@
#include "config_test_env.h"
#include "license_request.h"
#include "logger_global.h"
#include "test_host.h"
#include "url_request.h"
@@ -29,6 +30,7 @@
#define WALL_NOW std::chrono::high_resolution_clock::now()
TestHost* g_host = nullptr;
widevine::StderrLogger g_stderr_logger;
namespace widevine {
@@ -145,6 +147,8 @@ class EventListener : public Cdm::IEventListener {
}
void onKeyStatusesChange(const std::string& session_id,
bool has_new_usable_key) override {}
void onExpirationChange(const std::string& session_id,
int64_t new_expiration) override {}
void onRemoveComplete(const std::string& session_id) override {}
std::vector<MessageInfo> messages;
@@ -182,6 +186,10 @@ class GlobalEnv : public testing::Environment {
: init_func_(init_func), cert_(cert) {}
void SetUp() override {
// Manually set the logger because `TestHost` makes logging calls before
// the global logger is set in |init_func_|.
g_logger = &g_stderr_logger;
g_host = new TestHost;
if (!cert_.empty()) g_host->per_origin_storage().write("cert.bin", cert_);

View File

@@ -22,7 +22,7 @@ constexpr char kInitName[] =
"_ZN8widevine3Cdm10initializeENS0_16SecureOutputTypeEPNS0_8IStorageEPNS0_"
"6IClockEPNS0_6ITimerEPNS0_7ILoggerENS0_8LogLevelE";
constexpr char kCreateName[] =
"_ZN8widevine3Cdm6createEPNS0_14IEventListenerEPNS0_8IStorageEb";
"_ZN8widevine3Cdm6createEPNS0_14IEventListenerEPNS0_8IStorageEbb";
bool ReadFile(const std::string& path, std::string* output) {
constexpr size_t kReadSize = 8 * 1024;

View File

@@ -8,10 +8,12 @@
#include <unordered_set>
#include "cdm_version.h"
#include "device_files.pb.h"
#include "file_store.h"
#include "log.h"
using namespace widevine;
using video_widevine_client::sdk::SavedStorage;
namespace {
@@ -120,6 +122,20 @@ void TestHost::Storage::Reset() {
files_.clear();
}
bool TestHost::Storage::LoadFromString(const std::string& data) {
SavedStorage proto;
if (!proto.ParseFromString(data)) return false;
Reset();
files_.insert(proto.files().begin(), proto.files().end());
return true;
}
bool TestHost::Storage::SaveToString(std::string* data) const {
SavedStorage proto;
proto.mutable_files()->insert(files_.begin(), files_.end());
return proto.SerializeToString(data);
}
bool TestHost::Storage::read(const std::string& name, std::string* data) {
StorageMap::iterator it = files_.find(name);
bool ok = it != files_.end();

View File

@@ -28,6 +28,10 @@ class TestHost : public widevine::Cdm::IClock,
~Storage() override {}
void Reset();
// Save and load the storage from a string buffer so it can be on disk.
bool LoadFromString(const std::string& data);
bool SaveToString(std::string* data) const;
// Reset the file system to contain the specified files.
void ResetFiles(const StorageMap& files) { files_ = files; };
const StorageMap& files() const { return files_; }