Added CDM support for Watermarking reporting.

[ Merge of http://go/wvgerrit/148552 ]

Extended the CDM layer to report OEMCrypto's watermarking support.
The reporting of watermarking comes in three (3) mechanisms:
1) ClientCapabilities in license requests
2) CryptoSession metrics when queried to OEMCrypto
3) String property query by apps

If OEMCrypto implementents OEMCrypto_GetWatermarkingSupport(), then
the reported watermarking support by the CDM will match that of
OEMCrypto.

If OEMCrypto does not implement OEMCrypto_GetWatermarkingSupport()
or an error occurs, it is assumed that OEMCrypto does not support
watermarking, and the CDM will report "Not Supported".

Bug: 226443788
Test: run_x86_64_tests request_license_test and license_unittest
Change-Id: Id929a356c395e6bcf45d371ee6887eec40d35329
This commit is contained in:
Alex Dale
2022-03-23 17:00:32 -07:00
parent 0a65e3ba32
commit 97f3544866
22 changed files with 191 additions and 9 deletions

View File

@@ -239,6 +239,7 @@ void WVDrmFactory::printCdmProperties(int fd) {
{"analog capabilities:", wvcdm::QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES},
{"can disable analog output:",
wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT},
{"watermarking support:", wvcdm::QUERY_KEY_WATERMARKING_SUPPORT},
};
string value;

View File

@@ -374,6 +374,9 @@ void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics,
FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_provisioning_time_us, indent);
FORMAT_OPTIONAL_VALUE(oemcrypto_minor_api_version, indent);
FORMAT_OPTIONAL_VALUE(oemcrypto_maximum_usage_table_header_size, indent);
// OEMCrypto V17 metrics below.
FORMAT_OPTIONAL_VALUE(oemcrypto_watermarking_support, indent);
}
void FormatSessionMetrics(const WvCdmMetrics_SessionMetrics& metrics,

View File

@@ -216,6 +216,11 @@ class CryptoSession {
std::string* info);
virtual bool GetBuildInformation(std::string* info);
virtual bool GetWatermarkingSupport(CdmWatermarkingSupport* support);
virtual bool GetWatermarkingSupport(
RequestedSecurityLevel requested_security_level,
CdmWatermarkingSupport* support);
virtual bool GetMaximumUsageTableEntries(
RequestedSecurityLevel security_level, size_t* number_of_entries);

View File

@@ -70,6 +70,8 @@ size_t OEMCrypto_MaximumUsageTableHeaderSize(RequestedSecurityLevel level);
OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert,
size_t* public_cert_length,
RequestedSecurityLevel level);
OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(
RequestedSecurityLevel level);
} // namespace wvcdm
/* The following functions are deprecated in OEMCrypto v13. They are defined

View File

@@ -110,6 +110,7 @@ static const std::string QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES =
"AnalogOutputCapabilities";
static const std::string QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT =
"CanDisableAnalogOutput";
static const std::string QUERY_KEY_WATERMARKING_SUPPORT = "WatermarkingSupport";
static const std::string QUERY_VALUE_TRUE = "True";
static const std::string QUERY_VALUE_FALSE = "False";
@@ -137,6 +138,9 @@ static const std::string QUERY_VALUE_OEM_CERTIFICATE = "OEMCertificate";
static const std::string QUERY_VALUE_CGMS_A = "CGMS-A";
static const std::string QUERY_VALUE_BOOT_CERTIFICATE_CHAIN =
"BootCertificateChain";
static const std::string QUERY_VALUE_NOT_SUPPORTED = "NotSupported";
static const std::string QUERY_VALUE_CONFIGURABLE = "Configurable";
static const std::string QUERY_VALUE_ALWAYS_ON = "AlwaysOn";
static const std::string ISO_BMFF_VIDEO_MIME_TYPE = "video/mp4";
static const std::string ISO_BMFF_AUDIO_MIME_TYPE = "audio/mp4";

View File

@@ -593,6 +593,12 @@ enum CdmProvisioningStatus : int32_t {
kNeedsOemCertProvisioning,
};
enum CdmWatermarkingSupport : int32_t {
kWatermarkingNotSupported,
kWatermarkingConfigurable,
kWatermarkingAlwaysOn
};
class CdmKeyAllowedUsage {
public:
CdmKeyAllowedUsage() { Clear(); }
@@ -835,6 +841,7 @@ const char* CdmSecurityLevelToString(CdmSecurityLevel security_level);
const char* CdmUsageEntryStorageTypeToString(CdmUsageEntryStorageType type);
const char* RequestedSecurityLevelToString(
RequestedSecurityLevel security_level);
const char* CdmWatermarkingSupportToString(CdmWatermarkingSupport support);
// Converts a generic, unknown enum value to a string representation
// containing its numeric value.
// The pointer returned from this function is thread_local.

View File

@@ -795,6 +795,28 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
}
return NO_ERROR;
}
if (query_token == QUERY_KEY_WATERMARKING_SUPPORT) {
CdmWatermarkingSupport support;
if (!crypto_session->GetWatermarkingSupport(security_level, &support)) {
// Assume not supported.
support = kWatermarkingNotSupported;
}
switch (support) {
case kWatermarkingNotSupported:
*query_response = QUERY_VALUE_NOT_SUPPORTED;
break;
case kWatermarkingConfigurable:
*query_response = QUERY_VALUE_CONFIGURABLE;
break;
case kWatermarkingAlwaysOn:
*query_response = QUERY_VALUE_ALWAYS_ON;
break;
default:
LOGW("Unknown watermarking support: %d", static_cast<int>(support));
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
CdmResponseType status;
M_TIME(status = crypto_session->Open(security_level),

View File

@@ -343,6 +343,28 @@ CdmResponseType ClientIdentification::Prepare(
}
}
if (is_license_request_) {
CdmWatermarkingSupport support;
if (!crypto_session_->GetWatermarkingSupport(&support)) {
// Assume not supported.
support = kWatermarkingNotSupported;
}
switch (support) {
case kWatermarkingNotSupported:
client_capabilities->set_watermarking_support(
ClientCapabilities::WATERMARKING_NOT_SUPPORTED);
break;
case kWatermarkingConfigurable:
client_capabilities->set_watermarking_support(
ClientCapabilities::WATERMARKING_CONFIGURABLE);
break;
case kWatermarkingAlwaysOn:
client_capabilities->set_watermarking_support(
ClientCapabilities::WATERMARKING_ALWAYS_ON);
break;
}
}
return NO_ERROR;
}

View File

@@ -2306,6 +2306,41 @@ bool CryptoSession::GetBuildInformation(RequestedSecurityLevel security_level,
return true;
}
bool CryptoSession::GetWatermarkingSupport(CdmWatermarkingSupport* support) {
RETURN_IF_NOT_OPEN(false);
return GetWatermarkingSupport(requested_security_level_, support);
}
bool CryptoSession::GetWatermarkingSupport(
RequestedSecurityLevel security_level, CdmWatermarkingSupport* support) {
LOGV("security_level = %s", RequestedSecurityLevelToString(security_level));
RETURN_IF_UNINITIALIZED(false);
RETURN_IF_NULL(support, false);
const OEMCrypto_WatermarkingSupport oec_support = WithOecReadLock(
"GetWatermarkingSupport",
[&] { return OEMCrypto_GetWatermarkingSupport(security_level); });
switch (oec_support) {
case OEMCrypto_WatermarkingNotSupported:
*support = kWatermarkingNotSupported;
break;
case OEMCrypto_WatermarkingConfigurable:
*support = kWatermarkingConfigurable;
break;
case OEMCrypto_WatermarkingAlwaysOn:
*support = kWatermarkingAlwaysOn;
break;
case OEMCrypto_WatermarkingError:
default:
LOGE("GetWatermarkingSupport error: security_level = %s, result = %d",
RequestedSecurityLevelToString(security_level),
static_cast<int>(oec_support));
metrics_->oemcrypto_watermarking_support_.SetError(oec_support);
return false;
}
metrics_->oemcrypto_watermarking_support_.Record(oec_support);
return true;
}
bool CryptoSession::GetMaximumUsageTableEntries(
RequestedSecurityLevel security_level, size_t* number_of_entries) {
LOGV("Getting maximum usage table entries: security_level = %s",

View File

@@ -908,6 +908,13 @@ message ClientIdentification {
ANALOG_OUTPUT_SUPPORTS_CGMS_A = 3;
}
enum WatermarkingSupport {
WATERMARKING_SUPPORT_UNKNOWN = 0;
WATERMARKING_NOT_SUPPORTED = 1;
WATERMARKING_CONFIGURABLE = 2;
WATERMARKING_ALWAYS_ON = 3;
}
optional bool client_token = 1 [default = false];
optional bool session_token = 2 [default = false];
optional bool video_resolution_constraints = 3 [default = false];
@@ -932,6 +939,10 @@ message ClientIdentification {
// the resource rating is unavailable or reporting erroneous values
// for that device.
optional uint32 resource_rating_tier = 12 [default = 0];
// Watermarking support of OEMCrypto was introduced in v17.
// Support is optional.
// Value is only required to be set for license requests.
optional WatermarkingSupport watermarking_support = 13;
}
message ClientCredentials {

View File

@@ -1896,6 +1896,17 @@ OEMCryptoResult OEMCrypto_SetDebugIgnoreKeyboxCount(uint32_t count) {
OEMCryptoResult OEMCrypto_SetAllowTestKeybox(bool allow) {
return SetAllowTestKeybox(allow);
}
OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(
wvcdm::RequestedSecurityLevel level) {
if (!gAdapter) return OEMCrypto_WatermarkingError;
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
if (!fcn) return OEMCrypto_WatermarkingError;
if (fcn->version < 17) return OEMCrypto_WatermarkingNotSupported;
if (fcn->GetWatermarkingSupport == nullptr)
return OEMCrypto_WatermarkingError;
return fcn->GetWatermarkingSupport();
}
} // namespace wvcdm
extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id,
@@ -3403,12 +3414,7 @@ extern "C" OEMCryptoResult OEMCrypto_GetDTCP2Capability(
return fcn->GetDTCP2Capability(capability);
}
extern "C" OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport() {
if (!gAdapter) return OEMCrypto_WatermarkingError;
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
if (!fcn) return OEMCrypto_WatermarkingError;
if (fcn->version < 17) return OEMCrypto_WatermarkingError;
if (fcn->GetWatermarkingSupport == nullptr)
return OEMCrypto_WatermarkingError;
return fcn->GetWatermarkingSupport();
extern "C" OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(
void) {
return wvcdm::OEMCrypto_GetWatermarkingSupport(kLevelDefault);
}

View File

@@ -119,6 +119,18 @@ const char* RequestedSecurityLevelToString(
return UnknownValueRep(security_level);
}
const char* CdmWatermarkingSupportToString(CdmWatermarkingSupport support) {
switch (support) {
case kWatermarkingNotSupported:
return QUERY_VALUE_NOT_SUPPORTED.c_str();
case kWatermarkingConfigurable:
return QUERY_VALUE_CONFIGURABLE.c_str();
case kWatermarkingAlwaysOn:
return QUERY_VALUE_ALWAYS_ON.c_str();
}
return UnknownValueRep(support);
}
const char* UnknownEnumValueToString(int value) {
snprintf(tl_unknown_rep_buf, sizeof(tl_unknown_rep_buf), "<unknown(%d)>",
value);

View File

@@ -135,6 +135,7 @@ const std::string kFakeKeyTooLong =
a2bs_hex("d4bc8605d662878a46adb2adb6bf3c0b30a54a0c2f");
const std::string kFakeKeyTooShort = a2bs_hex("06e247e7f924208011");
const std::string kFakeIv = a2bs_hex("3d515a3ee0be1687080ac59da9e0d69a");
const std::string kFakeBuildInfo = "Mock Crypto Session - License Test";
class MockCryptoSession : public TestCryptoSession {
public:
@@ -154,6 +155,11 @@ class MockCryptoSession : public TestCryptoSession {
MOCK_METHOD(CdmResponseType, LoadEntitledContentKeys,
(const std::vector<CryptoKey>& key_array), (override));
MOCK_METHOD(bool, GetResourceRatingTier, (uint32_t*), (override));
MOCK_METHOD(bool, GetWatermarkingSupport, (CdmWatermarkingSupport*),
(override));
MOCK_METHOD(bool, GetBuildInformation, (std::string*), (override));
CdmSecurityLevel GetSecurityLevel() override { return kSecurityLevelL1; }
};
class MockPolicyEngine : public PolicyEngine {
@@ -318,6 +324,11 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
.WillOnce(DoAll(SetArgPointee<1>(kFakeCoreMessage),
SetArgPointee<2>(kLicenseRequestSignature),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, GetBuildInformation(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kFakeBuildInfo), Return(true)));
EXPECT_CALL(*crypto_session_, GetWatermarkingSupport(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kWatermarkingConfigurable), Return(true)));
CreateCdmLicense();
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
@@ -385,6 +396,8 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
ClientCapabilities::ECC_SECP384R1,
ClientCapabilities::ECC_SECP521R1));
EXPECT_TRUE(client_capabilities.has_resource_rating_tier());
EXPECT_EQ(client_capabilities.watermarking_support(),
ClientCapabilities::WATERMARKING_CONFIGURABLE);
// Verify Content Identification
const LicenseRequest_ContentIdentification& content_id =
@@ -442,6 +455,11 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
.WillOnce(DoAll(SetArgPointee<1>(kFakeCoreMessage),
SetArgPointee<2>(kLicenseRequestSignature),
Return(NO_ERROR)));
EXPECT_CALL(*crypto_session_, GetBuildInformation(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kFakeBuildInfo), Return(true)));
EXPECT_CALL(*crypto_session_, GetWatermarkingSupport(NotNull()))
.WillOnce(
DoAll(SetArgPointee<0>(kWatermarkingNotSupported), Return(true)));
CreateCdmLicense();
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
@@ -509,6 +527,8 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
ClientCapabilities::ECC_SECP384R1,
ClientCapabilities::ECC_SECP521R1));
EXPECT_EQ(resource_rating_tier, client_capabilities.resource_rating_tier());
EXPECT_EQ(client_capabilities.watermarking_support(),
ClientCapabilities::WATERMARKING_NOT_SUPPORTED);
// Verify Content Identification
const LicenseRequest_ContentIdentification& content_id =

View File

@@ -297,6 +297,7 @@ class CryptoMetrics {
oemcrypto_generate_certificate_key_pair_;
EventMetric<kOemCryptoResultFieldNumber, OEMCryptoResult>
oemcrypto_install_oem_private_key_;
ValueMetric<int> oemcrypto_watermarking_support_;
}; // class CryptoMetrics
// This class contains session-scoped metrics. All properties and

View File

@@ -209,6 +209,8 @@ void CryptoMetrics::Serialize(
oemcrypto_minor_api_version_.ToProto());
crypto_metrics->set_allocated_oemcrypto_maximum_usage_table_header_size(
oemcrypto_maximum_usage_table_header_size_.ToProto());
crypto_metrics->set_allocated_oemcrypto_watermarking_support(
oemcrypto_watermarking_support_.ToProto());
}
SessionMetrics::SessionMetrics() : session_id_(""), completed_(false) {}

View File

@@ -92,7 +92,7 @@ message WvCdmMetrics {
// This contains metrics that were captured at the CryptoSession level. These
// include CryptoSession metrics and most OEMCrypto metrics.
// next id: 85
// next id: 86
message CryptoMetrics {
// Crypto Session Metrics.
optional ValueMetric crypto_session_security_level = 1;
@@ -192,6 +192,7 @@ message WvCdmMetrics {
repeated DistributionMetric oemcrypto_load_provisioning_time_us = 82;
optional ValueMetric oemcrypto_minor_api_version = 83;
optional ValueMetric oemcrypto_maximum_usage_table_header_size = 84;
optional ValueMetric oemcrypto_watermarking_support = 85;
}
// This contains metrics that were captured within a CdmSession. This contains

View File

@@ -443,6 +443,8 @@ TEST_F(CryptoMetricsTest, AllCryptoMetrics) {
crypto_metrics.oemcrypto_resource_rating_tier_.Record(123);
crypto_metrics.oemcrypto_minor_api_version_.Record(234);
crypto_metrics.oemcrypto_maximum_usage_table_header_size_.Record(321);
crypto_metrics.oemcrypto_watermarking_support_.Record(
OEMCrypto_WatermarkingAlwaysOn);
WvCdmMetrics::CryptoMetrics actual;
crypto_metrics.Serialize(&actual);
@@ -534,6 +536,8 @@ TEST_F(CryptoMetricsTest, AllCryptoMetrics) {
EXPECT_EQ(234, actual.oemcrypto_minor_api_version().int_value());
EXPECT_EQ(321,
actual.oemcrypto_maximum_usage_table_header_size().int_value());
EXPECT_EQ(static_cast<int>(OEMCrypto_WatermarkingAlwaysOn),
actual.oemcrypto_watermarking_support().int_value());
}
} // namespace metrics
} // namespace wvcdm

View File

@@ -5232,6 +5232,14 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) {
decryptor_->QueryStatus(
kLevelDefault, wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT, &value));
EXPECT_THAT(kCanDisableAnalogOutput, Contains(value));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->QueryStatus(
kLevelDefault, wvcdm::QUERY_KEY_WATERMARKING_SUPPORT, &value));
EXPECT_TRUE(value == wvcdm::QUERY_VALUE_NOT_SUPPORTED ||
value == wvcdm::QUERY_VALUE_CONFIGURABLE ||
value == wvcdm::QUERY_VALUE_ALWAYS_ON)
<< "Watermarking support";
}
TEST_F(WvCdmRequestLicenseTest, QueryStatusL3) {
@@ -5372,6 +5380,14 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatusL3) {
decryptor_->QueryStatus(
kLevel3, wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT, &value));
EXPECT_THAT(kCanDisableAnalogOutput, Contains(value));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->QueryStatus(
kLevelDefault, wvcdm::QUERY_KEY_WATERMARKING_SUPPORT, &value));
EXPECT_TRUE(value == wvcdm::QUERY_VALUE_NOT_SUPPORTED ||
value == wvcdm::QUERY_VALUE_CONFIGURABLE ||
value == wvcdm::QUERY_VALUE_ALWAYS_ON)
<< "Watermarking support";
}
TEST_F(WvCdmRequestLicenseTest, QueryOemCryptoSessionId) {

View File

@@ -1149,6 +1149,8 @@ Status WVDrmPlugin::unprovisionDevice() {
} else {
value = kDisable;
}
} else if (name == "watermarkingSupport") {
status = queryProperty(wvcdm::QUERY_KEY_WATERMARKING_SUPPORT, value);
} else {
ALOGE("App requested unknown string property %s", name.c_str());
*_aidl_return = value;

View File

@@ -1259,6 +1259,8 @@ Return<void> WVDrmPlugin::getPropertyString(const hidl_string& propertyName,
} else {
value = kDisable;
}
} else if (name == "watermarkingSupport") {
status = queryProperty(wvcdm::QUERY_KEY_WATERMARKING_SUPPORT, value);
} else {
ALOGE("App requested unknown string property %s", name.c_str());
status = Status::ERROR_DRM_CANNOT_HANDLE;

View File

@@ -216,6 +216,7 @@ void WVDrmFactory::printCdmProperties(FILE* out) {
{"analog capabilities:", wvcdm::QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES},
{"can disable analog output:",
wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT},
{"watermarking support:", wvcdm::QUERY_KEY_WATERMARKING_SUPPORT},
};
std::string value;

View File

@@ -374,6 +374,9 @@ void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics,
FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_provisioning_time_us, indent);
FORMAT_OPTIONAL_VALUE(oemcrypto_minor_api_version, indent);
FORMAT_OPTIONAL_VALUE(oemcrypto_maximum_usage_table_header_size, indent);
// OEMCrypto V17 metrics below.
FORMAT_OPTIONAL_VALUE(oemcrypto_watermarking_support, indent);
}
void FormatSessionMetrics(const WvCdmMetrics_SessionMetrics& metrics,