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:
Rahul Frias
2018-11-30 13:07:25 -08:00
parent e01b559bb7
commit afd11c0da5
10 changed files with 222 additions and 3 deletions

View File

@@ -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,

View File

@@ -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";

View File

@@ -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");

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 =

View File

@@ -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());
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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.