Add support for Resource Rating Tiers
[ Merge of http://go/wvgerrit/67324 ] This introduces the ability to query resource rating tier information through the plugin and CDM. Resource rating tiers are also sent in the client identification portion of the license request. Bug: 117112392 Test: WV unit/integration tests Change-Id: I68ac6dfc4362f61150af822bd526e346b5cc4bf7
This commit is contained in:
@@ -149,6 +149,7 @@ class CryptoSession {
|
||||
virtual bool IsSrmUpdateSupported();
|
||||
virtual bool LoadSrm(const std::string& srm);
|
||||
|
||||
virtual bool GetResourceRatingTier(uint32_t* tier);
|
||||
virtual bool GetBuildInformation(std::string* info);
|
||||
|
||||
virtual CdmResponseType GenericEncrypt(const std::string& in_buffer,
|
||||
|
||||
@@ -26,6 +26,14 @@ static const size_t CERTIFICATE_DATA_SIZE = 4 * 1024;
|
||||
// (NaN in JS translates to 0 in unix timestamp).
|
||||
static const int64_t NEVER_EXPIRES = 0;
|
||||
|
||||
// Resource rating tiers
|
||||
static const uint32_t RESOURCE_RATING_TIER_LOW = 1u;
|
||||
static const uint32_t RESOURCE_RATING_TIER_MEDIUM = 2u;
|
||||
static const uint32_t RESOURCE_RATING_TIER_HIGH = 3u;
|
||||
|
||||
// OEMCrypto features by version
|
||||
static const uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER = 15;
|
||||
|
||||
static const char SESSION_ID_PREFIX[] = "sid";
|
||||
static const char KEY_SET_ID_PREFIX[] = "ksid";
|
||||
static const char KEY_SYSTEM[] = "com.widevine";
|
||||
@@ -71,6 +79,7 @@ static const std::string QUERY_KEY_CURRENT_SRM_VERSION = "CurrentSRMVersion";
|
||||
static const std::string QUERY_KEY_SRM_UPDATE_SUPPORT = "SRMUpdateSupport";
|
||||
// whether OEM supports SRM update
|
||||
static const std::string QUERY_KEY_WVCDM_VERSION = "WidevineCdmVersion";
|
||||
static const std::string QUERY_KEY_RESOURCE_RATING_TIER = "ResourceRatingTier";
|
||||
static const std::string QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION =
|
||||
"OemCryptoBuildInformation";
|
||||
|
||||
|
||||
@@ -642,6 +642,16 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
}
|
||||
|
||||
*query_response = cdm_version;
|
||||
} else if (query_token == QUERY_KEY_RESOURCE_RATING_TIER) {
|
||||
uint32_t tier;
|
||||
if (!crypto_session->GetResourceRatingTier(&tier)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetResourceRatingTier failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
std::ostringstream tier_stream;
|
||||
tier_stream << tier;
|
||||
*query_response = tier_stream.str();
|
||||
} else if (query_token == QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION) {
|
||||
if (!crypto_session->GetBuildInformation(query_response)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetBuildInformation failed");
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
const std::string kKeyCompanyName = "company_name";
|
||||
@@ -254,6 +255,15 @@ CdmResponseType ClientIdentification::Prepare(
|
||||
client_capabilities->set_analog_output_capabilities(video_widevine::ClientIdentification_ClientCapabilities_AnalogOutputCapabilities_ANALOG_OUTPUT_UNKNOWN);
|
||||
}
|
||||
|
||||
uint32_t version, tier;
|
||||
if (crypto_session_->GetApiVersion(&version)) {
|
||||
if (version >= OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER) {
|
||||
if (crypto_session_->GetResourceRatingTier(&tier)) {
|
||||
client_capabilities->set_resource_rating_tier(tier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@@ -1773,6 +1773,25 @@ bool CryptoSession::LoadSrm(const std::string& srm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GetResourceRatingTier(uint32_t* tier) {
|
||||
LOGV("GetResourceRatingTier");
|
||||
if (!initialized_) return false;
|
||||
if (tier == nullptr) {
|
||||
LOGE("tier destination not provided");
|
||||
return false;
|
||||
}
|
||||
*tier = OEMCrypto_ResourceRatingTier(requested_security_level_);
|
||||
if (*tier < RESOURCE_RATING_TIER_LOW || *tier > RESOURCE_RATING_TIER_HIGH) {
|
||||
uint32_t api_version;
|
||||
if (GetApiVersion(&api_version)) {
|
||||
if (api_version >= OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER) {
|
||||
LOGW("GetResourceRatingTier: invalid resource rating tier: %d", *tier);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GetBuildInformation(std::string* info) {
|
||||
LOGV("GetBuildInformation");
|
||||
if (!initialized_) return false;
|
||||
|
||||
@@ -147,6 +147,7 @@ class MockCryptoSession : public TestCryptoSession {
|
||||
MOCK_METHOD3(PrepareRequest, bool(const std::string&, bool, std::string*));
|
||||
MOCK_METHOD1(LoadEntitledContentKeys,
|
||||
CdmResponseType(const std::vector<CryptoKey>& key_array));
|
||||
MOCK_METHOD1(GetResourceRatingTier, bool(uint32_t*));
|
||||
};
|
||||
|
||||
class MockPolicyEngine : public PolicyEngine {
|
||||
@@ -319,7 +320,8 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
SetArgPointee<1>(max_hdcp_version), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, GetSupportedCertificateTypes(NotNull()));
|
||||
EXPECT_CALL(*crypto_session_, GetApiVersion(NotNull()))
|
||||
.WillOnce(
|
||||
.Times(2)
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(crypto_session_api_version), Return(true)));
|
||||
EXPECT_CALL(*clock_, GetCurrentTime()).WillOnce(Return(kLicenseStartTime));
|
||||
EXPECT_CALL(*crypto_session_, GenerateNonce(NotNull()))
|
||||
@@ -393,6 +395,131 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_2048,
|
||||
video_widevine::
|
||||
ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_3072));
|
||||
EXPECT_FALSE(client_capabilities.has_resource_rating_tier());
|
||||
|
||||
// Verify Content Identification
|
||||
const LicenseRequest_ContentIdentification& content_id =
|
||||
license_request.content_id();
|
||||
ASSERT_TRUE(content_id.has_cenc_id_deprecated());
|
||||
EXPECT_FALSE(content_id.has_webm_id_deprecated());
|
||||
EXPECT_FALSE(content_id.has_existing_license());
|
||||
|
||||
const ::video_widevine::LicenseRequest_ContentIdentification_CencDeprecated&
|
||||
cenc_id = content_id.cenc_id_deprecated();
|
||||
EXPECT_TRUE(std::equal(cenc_id.pssh(0).begin(), cenc_id.pssh(0).end(),
|
||||
kCencPssh.begin()));
|
||||
EXPECT_EQ(video_widevine::STREAMING, cenc_id.license_type());
|
||||
EXPECT_TRUE(std::equal(cenc_id.request_id().begin(),
|
||||
cenc_id.request_id().end(), kCryptoRequestId.begin()));
|
||||
|
||||
// Verify other license request fields
|
||||
EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_NEW,
|
||||
license_request.type());
|
||||
EXPECT_EQ(kLicenseStartTime, license_request.request_time());
|
||||
EXPECT_EQ(video_widevine::VERSION_2_1,
|
||||
license_request.protocol_version());
|
||||
EXPECT_EQ(kNonce, license_request.key_control_nonce());
|
||||
}
|
||||
|
||||
TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
|
||||
bool usage_information_support = true;
|
||||
CryptoSession::HdcpCapability current_hdcp_version = HDCP_NO_DIGITAL_OUTPUT;
|
||||
CryptoSession::HdcpCapability max_hdcp_version = HDCP_V2_1;
|
||||
uint32_t crypto_session_api_version = 15;
|
||||
uint32_t resource_rating_tier = RESOURCE_RATING_TIER_LOW;
|
||||
|
||||
EXPECT_CALL(*crypto_session_, IsOpen())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*crypto_session_, GenerateRequestId(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kCryptoRequestId), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, UsageInformationSupport(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(usage_information_support), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, GetHdcpCapabilities(NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(current_hdcp_version),
|
||||
SetArgPointee<1>(max_hdcp_version), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, GetSupportedCertificateTypes(NotNull()));
|
||||
EXPECT_CALL(*crypto_session_, GetApiVersion(NotNull()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(crypto_session_api_version), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, GetResourceRatingTier(NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(resource_rating_tier), Return(true)));
|
||||
EXPECT_CALL(*clock_, GetCurrentTime()).WillOnce(Return(kLicenseStartTime));
|
||||
EXPECT_CALL(*crypto_session_, GenerateNonce(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kNonce), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, PrepareRequest(_, Eq(false), NotNull()))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<2>(kLicenseRequestSignature), Return(true)));
|
||||
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(
|
||||
kToken, kClientTokenDrmCert, kEmptyString, true,
|
||||
kDefaultServiceCertificate, crypto_session_, policy_engine_));
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmKeyMessage signed_request;
|
||||
std::string server_url;
|
||||
EXPECT_EQ(cdm_license_->PrepareKeyRequest(
|
||||
*init_data_, kLicenseTypeStreaming, app_parameters,
|
||||
&signed_request, &server_url), KEY_MESSAGE);
|
||||
|
||||
EXPECT_TRUE(!signed_request.empty());
|
||||
|
||||
// Verify signed message
|
||||
SignedMessage signed_message;
|
||||
EXPECT_TRUE(signed_message.ParseFromString(signed_request));
|
||||
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type());
|
||||
EXPECT_TRUE(signed_message.has_signature());
|
||||
EXPECT_TRUE(std::equal(signed_message.signature().begin(),
|
||||
signed_message.signature().end(),
|
||||
kLicenseRequestSignature.begin()));
|
||||
EXPECT_TRUE(!signed_message.msg().empty());
|
||||
|
||||
// Verify license request
|
||||
LicenseRequest license_request;
|
||||
EXPECT_TRUE(license_request.ParseFromString(signed_message.msg()));
|
||||
|
||||
// Verify Client Identification
|
||||
const ClientIdentification& client_id = license_request.client_id();
|
||||
EXPECT_EQ(video_widevine::
|
||||
ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE,
|
||||
client_id.type());
|
||||
EXPECT_TRUE(std::equal(client_id.token().begin(), client_id.token().end(),
|
||||
kToken.begin()));
|
||||
|
||||
EXPECT_LT(0, client_id.client_info_size());
|
||||
for (int i = 0; i < client_id.client_info_size(); ++i) {
|
||||
const ::video_widevine::ClientIdentification_NameValue&
|
||||
name_value = client_id.client_info(i);
|
||||
EXPECT_TRUE(!name_value.name().empty());
|
||||
EXPECT_TRUE(!name_value.value().empty());
|
||||
}
|
||||
|
||||
EXPECT_FALSE(client_id.has_provider_client_token());
|
||||
EXPECT_FALSE(client_id.has_license_counter());
|
||||
|
||||
const ::video_widevine::ClientIdentification_ClientCapabilities&
|
||||
client_capabilities = client_id.client_capabilities();
|
||||
EXPECT_FALSE(client_capabilities.has_client_token());
|
||||
EXPECT_TRUE(client_capabilities.has_session_token());
|
||||
EXPECT_FALSE(client_capabilities.video_resolution_constraints());
|
||||
EXPECT_EQ(video_widevine::
|
||||
ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1,
|
||||
client_capabilities.max_hdcp_version());
|
||||
EXPECT_EQ(crypto_session_api_version,
|
||||
client_capabilities.oem_crypto_api_version());
|
||||
|
||||
EXPECT_THAT(
|
||||
client_capabilities.supported_certificate_key_type(),
|
||||
UnorderedElementsAre(
|
||||
video_widevine::
|
||||
ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_2048,
|
||||
video_widevine::
|
||||
ClientIdentification_ClientCapabilities_CertificateKeyType_RSA_3072));
|
||||
EXPECT_EQ(resource_rating_tier,
|
||||
client_capabilities.resource_rating_tier());
|
||||
|
||||
// Verify Content Identification
|
||||
const LicenseRequest_ContentIdentification& content_id =
|
||||
|
||||
@@ -4140,8 +4140,27 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) {
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.QueryStatus(
|
||||
kLevelDefault, wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION,
|
||||
&value));
|
||||
kLevelDefault, wvcdm::QUERY_KEY_RESOURCE_RATING_TIER, &value));
|
||||
ss.clear();
|
||||
ss.str(value);
|
||||
uint32_t resource_rating_tier;
|
||||
ss >> resource_rating_tier;
|
||||
ASSERT_FALSE(ss.fail());
|
||||
EXPECT_TRUE(ss.eof());
|
||||
|
||||
if (api_version >= OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER) {
|
||||
EXPECT_LE(RESOURCE_RATING_TIER_LOW, resource_rating_tier);
|
||||
EXPECT_GE(RESOURCE_RATING_TIER_HIGH, resource_rating_tier);
|
||||
} else {
|
||||
EXPECT_TRUE(resource_rating_tier < RESOURCE_RATING_TIER_LOW ||
|
||||
resource_rating_tier > RESOURCE_RATING_TIER_HIGH)
|
||||
<< "resource rating tier: " << resource_rating_tier;
|
||||
}
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.QueryStatus(kLevelDefault,
|
||||
wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION,
|
||||
&value));
|
||||
EXPECT_TRUE(!value.empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -524,6 +524,8 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
|
||||
return queryProperty(QUERY_KEY_CURRENT_SRM_VERSION, value);
|
||||
} else if (name == "SRMUpdateSupport") {
|
||||
return queryProperty(QUERY_KEY_SRM_UPDATE_SUPPORT, value);
|
||||
} else if (name == "resourceRatingTier") {
|
||||
return queryProperty(QUERY_KEY_RESOURCE_RATING_TIER, value);
|
||||
} else if (name == "oemCryptoBuildInformation") {
|
||||
return queryProperty(QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, value);
|
||||
} else {
|
||||
|
||||
@@ -1020,6 +1020,8 @@ Return<void> WVDrmPlugin::getPropertyString(const hidl_string& propertyName,
|
||||
status = queryProperty(wvcdm::QUERY_KEY_CURRENT_SRM_VERSION, value);
|
||||
} else if (name == "SRMUpdateSupport") {
|
||||
status = queryProperty(wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT, value);
|
||||
} else if (name == "resourceRatingTier") {
|
||||
status = queryProperty(wvcdm::QUERY_KEY_RESOURCE_RATING_TIER, value);
|
||||
} else if (name == "oemCryptoBuildInformation") {
|
||||
status = queryProperty(wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, value);
|
||||
} else {
|
||||
|
||||
@@ -109,6 +109,7 @@ using wvcdm::QUERY_KEY_SECURITY_LEVEL;
|
||||
using wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT;
|
||||
using wvcdm::QUERY_KEY_SYSTEM_ID;
|
||||
using wvcdm::QUERY_KEY_WVCDM_VERSION;
|
||||
using wvcdm::QUERY_KEY_RESOURCE_RATING_TIER;
|
||||
using wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION;
|
||||
using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||
@@ -1135,6 +1136,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
static const std::string oemCryptoApiVersion = "13";
|
||||
static const std::string currentSRMVersion = "1";
|
||||
static const std::string cdmVersion = "Infinity Minus 1";
|
||||
static const std::string resourceRatingTier = "1";
|
||||
static const std::string oemCryptoBuildInformation = "Mostly Harmless";
|
||||
drm_metrics::WvCdmMetrics expected_metrics;
|
||||
std::string serialized_metrics = wvcdm::a2bs_hex(kSerializedMetricsHex);
|
||||
@@ -1182,6 +1184,10 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
.WillOnce(DoAll(SetArgPointee<2>(cdmVersion),
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_RESOURCE_RATING_TIER, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(resourceRatingTier),
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(oemCryptoBuildInformation),
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
@@ -1291,6 +1297,20 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
||||
EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("resourceRatingTier"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_STREQ(resourceRatingTier.c_str(), stringResult.c_str());
|
||||
});
|
||||
|
||||
plugin.getPropertyString(
|
||||
hidl_string("oemCryptoBuildInformation"),
|
||||
[&](Status status, hidl_string stringResult) {
|
||||
ASSERT_EQ(Status::OK, status);
|
||||
EXPECT_STREQ(oemCryptoBuildInformation.c_str(), stringResult.c_str());
|
||||
});
|
||||
|
||||
// This call occurs before any open session or other call. This means
|
||||
// that the cdm identifer is not yet sealed, and metrics return empty
|
||||
// metrics data.
|
||||
|
||||
Reference in New Issue
Block a user