Merge MaxNumberOfSessions changes from CDM

Bug: 18377675

Implement new OEMCrypto function to get max number of sessions
https://widevine-internal-review.googlesource.com/#/c/12980/

Add oemcrypto static adapter for v9
https://widevine-internal-review.googlesource.com/#/c/13022/

Support new property to query MaxNumberOfSessions in CDM
https://widevine-internal-review.googlesource.com/#/c/13020/

Fix GetHdcpCapabilities incorrect return if not initialized
https://widevine-internal-review.googlesource.com/#/c/13210/

Change-Id: I02738c543cedd6e38d8826f845fec6cb2b1ede3c
This commit is contained in:
KongQun Yang
2015-02-19 16:52:23 -08:00
committed by John "Juce" Bruce
parent 891bd057f4
commit 23c95a1251
11 changed files with 199 additions and 74 deletions

View File

@@ -101,6 +101,7 @@ class CryptoSession {
virtual bool GetHdcpCapabilities(OemCryptoHdcpVersion* current,
OemCryptoHdcpVersion* max);
virtual bool GetRandom(size_t data_length, uint8_t* random_data);
virtual bool GetMaxNumberOfSessions(size_t* max);
private:
void Init();

View File

@@ -49,6 +49,7 @@ static const std::string QUERY_KEY_MAX_HDCP_LEVEL = "MaxHdcpLevel";
// maximum supported HDCP level
static const std::string QUERY_KEY_USAGE_SUPPORT = "UsageSupport";
// whether usage reporting is supported
static const std::string QUERY_KEY_MAX_NUMBER_OF_SESSIONS = "MaxNumberOfSessions";
static const std::string QUERY_VALUE_TRUE = "True";
static const std::string QUERY_VALUE_FALSE = "False";

View File

@@ -449,6 +449,12 @@ CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) {
supports_usage_reporting ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
}
size_t maximum_number_of_sessions;
success = crypto_session.GetMaxNumberOfSessions(&maximum_number_of_sessions);
if (success) {
(*key_info)[QUERY_KEY_MAX_NUMBER_OF_SESSIONS] = maximum_number_of_sessions;
}
return NO_ERROR;
}

View File

@@ -951,7 +951,13 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
bool CryptoSession::GetHdcpCapabilities(OemCryptoHdcpVersion* current_version,
OemCryptoHdcpVersion* max_version) {
LOGV("GetHdcpCapabilities: id=%ld", (uint32_t)oec_session_id_);
if (!initialized_) return UNKNOWN_ERROR;
if (!initialized_) return false;
if (current_version == NULL || max_version == NULL) {
LOGE(
"CryptoSession::GetHdcpCapabilities: |current_version|, "
"|max_version| cannot be NULL");
return false;
}
OEMCrypto_HDCP_Capability current, max;
OEMCryptoResult status = OEMCrypto_GetHDCPCapability(&current, &max);
@@ -980,4 +986,22 @@ bool CryptoSession::GetRandom(size_t data_length, uint8_t* random_data) {
return true;
}
bool CryptoSession::GetMaxNumberOfSessions(size_t* max) {
LOGV("GetMaxNumberOfSessions");
if (!initialized_) return false;
if (max == NULL) {
LOGE("CryptoSession::GetMaxNumberOfSessions: |max| cannot be NULL");
return false;
}
size_t max_sessions;
OEMCryptoResult status = OEMCrypto_GetMaxNumberOfSessions(&max_sessions);
if (OEMCrypto_SUCCESS != status) {
LOGW("OEMCrypto_GetMaxNumberOfSessions fails with %d", status);
return false;
}
*max = max_sessions;
return true;
}
}; // namespace wvcdm

View File

@@ -24,8 +24,10 @@
#include "properties.h"
using namespace wvoec3;
using wvcdm::kLevelDefault;
using wvcdm::kLevel3;
namespace wvcdm {
namespace {
typedef OEMCryptoResult (*L1_Initialize_t)(void);
typedef OEMCryptoResult (*L1_Terminate_t)(void);
@@ -138,6 +140,7 @@ typedef OEMCryptoResult (*L1_DeleteUsageEntry_t)(
const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length);
typedef OEMCryptoResult (*L1_DeleteUsageTable_t)();
typedef OEMCryptoResult (*L1_GetMaxNumberOfSessions_t)(size_t *maximum);
struct FunctionPointers {
uint32_t version;
@@ -175,6 +178,7 @@ struct FunctionPointers {
L1_ReportUsage_t ReportUsage;
L1_DeleteUsageEntry_t DeleteUsageEntry;
L1_DeleteUsageTable_t DeleteUsageTable;
L1_GetMaxNumberOfSessions_t GetMaxNumberOfSessions;
L1_LoadKeys_V8_t LoadKeys_V8;
L1_GenerateRSASignature_V8_t GenerateRSASignature_V8;
@@ -290,6 +294,9 @@ class Adapter {
LOOKUP(DeleteUsageEntry, OEMCrypto_DeleteUsageEntry);
LOOKUP(DeleteUsageTable, OEMCrypto_DeleteUsageTable);
}
if (level1_.version >= 10) {
LOOKUP(GetMaxNumberOfSessions, OEMCrypto_GetMaxNumberOfSessions);
}
if (OEMCrypto_SUCCESS == level1_.IsKeyboxValid()) {
return true;
}
@@ -353,6 +360,7 @@ class Adapter {
level3_.ReportUsage = Level3_ReportUsage;
level3_.DeleteUsageEntry = Level3_DeleteUsageEntry;
level3_.DeleteUsageTable = Level3_DeleteUsageTable;
level3_.GetMaxNumberOfSessions = Level3_GetMaxNumberOfSessions;
level3_.version = Level3_APIVersion();
}
@@ -366,13 +374,13 @@ class Adapter {
return result;
}
const FunctionPointers* get(SecurityLevel level) {
const FunctionPointers* get(wvcdm::SecurityLevel level) {
if (level1_valid_ && level == kLevelDefault) return &level1_;
return &level3_;
}
LevelSession get(OEMCrypto_SESSION session) {
AutoLock auto_lock(session_map_lock_);
wvcdm::AutoLock auto_lock(session_map_lock_);
map_iterator pair = session_map_.find(session);
if (pair == session_map_.end()) {
return LevelSession();
@@ -380,7 +388,8 @@ class Adapter {
return pair->second;
}
OEMCryptoResult OpenSession(OEMCrypto_SESSION* session, SecurityLevel level) {
OEMCryptoResult OpenSession(OEMCrypto_SESSION* session,
wvcdm::SecurityLevel level) {
LevelSession new_session;
OEMCryptoResult result;
if (level == kLevelDefault && level1_valid_) {
@@ -393,7 +402,7 @@ class Adapter {
*session = new_session.session + kLevel3Offset;
}
if (result == OEMCrypto_SUCCESS) {
AutoLock auto_lock(session_map_lock_);
wvcdm::AutoLock auto_lock(session_map_lock_);
// Make sure session is not already in my list of sessions.
while (session_map_.find(*session) != session_map_.end()) {
(*session)++;
@@ -404,7 +413,7 @@ class Adapter {
}
OEMCryptoResult CloseSession(OEMCrypto_SESSION session) {
AutoLock auto_lock(session_map_lock_);
wvcdm::AutoLock auto_lock(session_map_lock_);
map_iterator pair = session_map_.find(session);
if (pair == session_map_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
@@ -421,7 +430,7 @@ class Adapter {
struct FunctionPointers level1_;
struct FunctionPointers level3_;
std::map<OEMCrypto_SESSION, LevelSession> session_map_;
Lock session_map_lock_;
wvcdm::Lock session_map_lock_;
// This is just for debugging the map between session ids.
// If we add this to the level 3 session id, then the external session
// id will match the internal session id in the last two digits.
@@ -430,6 +439,72 @@ class Adapter {
static Adapter* kAdapter = 0;
} // namespace
namespace wvcdm {
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
return kAdapter->OpenSession(session, level);
}
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->IsKeyboxValid();
}
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->GetDeviceID(deviceID, idLength);
}
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->GetKeyData(keyData, keyDataLength);
}
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
size_t keyBoxLength,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->InstallKeybox(keybox, keyBoxLength);
}
uint32_t OEMCrypto_APIVersion(SecurityLevel level) {
if (!kAdapter) return 0;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return 0;
return fcn->APIVersion();
}
const char* OEMCrypto_SecurityLevel(SecurityLevel level) {
if (!kAdapter) return "";
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return "";
return fcn->SecurityLevel();
}
bool OEMCrypto_SupportsUsageTable(SecurityLevel level) {
if (!kAdapter) return false;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return false;
if (fcn->version == 8) return false;
return fcn->SupportsUsageTable();
}
}; // namespace wvcdm
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
if (kAdapter) {
delete kAdapter;
@@ -452,12 +527,6 @@ extern "C" OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session) {
return OEMCrypto_OpenSession(session, kLevelDefault);
}
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
return kAdapter->OpenSession(session, level);
}
extern "C" OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) {
if (!kAdapter) return OEMCrypto_ERROR_CLOSE_SESSION_FAILED;
return kAdapter->CloseSession(session);
@@ -550,52 +619,20 @@ extern "C" OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
return OEMCrypto_InstallKeybox(keybox, keyBoxLength, kLevelDefault);
}
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
size_t keyBoxLength,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->InstallKeybox(keybox, keyBoxLength);
}
extern "C" OEMCryptoResult OEMCrypto_IsKeyboxValid() {
return OEMCrypto_IsKeyboxValid(kLevelDefault);
}
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->IsKeyboxValid();
}
extern "C" OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
size_t* idLength) {
return OEMCrypto_GetDeviceID(deviceID, idLength, kLevelDefault);
}
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->GetDeviceID(deviceID, idLength);
}
extern "C" OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
size_t* keyDataLength) {
return OEMCrypto_GetKeyData(keyData, keyDataLength, kLevelDefault);
}
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
SecurityLevel level) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return fcn->GetKeyData(keyData, keyDataLength);
}
extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
size_t dataLength) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -676,24 +713,10 @@ extern "C" uint32_t OEMCrypto_APIVersion() {
return OEMCrypto_APIVersion(kLevelDefault);
}
uint32_t OEMCrypto_APIVersion(SecurityLevel level) {
if (!kAdapter) return 0;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return 0;
return fcn->APIVersion();
}
extern "C" const char* OEMCrypto_SecurityLevel() {
return OEMCrypto_SecurityLevel(kLevelDefault);
}
const char* OEMCrypto_SecurityLevel(SecurityLevel level) {
if (!kAdapter) return "";
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return "";
return fcn->SecurityLevel();
}
extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt(
OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length,
const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) {
@@ -751,14 +774,6 @@ extern "C" bool OEMCrypto_SupportsUsageTable() {
return OEMCrypto_SupportsUsageTable(kLevelDefault);
}
bool OEMCrypto_SupportsUsageTable(SecurityLevel level) {
if (!kAdapter) return false;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return false;
if( fcn->version == 8 ) return false;
return fcn->SupportsUsageTable();
}
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
@@ -828,4 +843,12 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageTable() {
return sts;
}
}; // namespace wvcdm
extern "C" OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t *maximum) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(kLevelDefault);
if (!fcn) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (fcn->version < 10) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return fcn->GetMaxNumberOfSessions(maximum);
}

View File

@@ -529,6 +529,17 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
return kErrorCDMGeneric;
}
value = status[QUERY_KEY_USAGE_SUPPORT].c_str();
} else if (name == "maxNumberOfSessions") {
CdmQueryMap status;
CdmResponseType res = mCDM->QueryStatus(&status);
if (res != wvcdm::NO_ERROR) {
ALOGE("Error querying CDM status: %u", res);
return mapCdmResponseType(res);
} else if (!status.count(QUERY_KEY_MAX_NUMBER_OF_SESSIONS)) {
ALOGE("CDM did not report maximum number of media drm sessions");
return kErrorCDMGeneric;
}
value = status[QUERY_KEY_MAX_NUMBER_OF_SESSIONS].c_str();
} else {
ALOGE("App requested unknown string property %s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE;

View File

@@ -708,6 +708,10 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
CdmQueryMap provisioningIDMap;
provisioningIDMap[QUERY_KEY_PROVISIONING_ID] = provisioningId;
static const string maxSessions = "18";
CdmQueryMap maxSessionsMap;
maxSessionsMap[QUERY_KEY_MAX_NUMBER_OF_SESSIONS] = maxSessions;
EXPECT_CALL(cdm, QueryStatus(_))
.WillOnce(DoAll(SetArgPointee<0>(l1Map),
Return(wvcdm::NO_ERROR)))
@@ -718,6 +722,8 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
.WillOnce(DoAll(SetArgPointee<0>(systemIDMap),
Return(wvcdm::NO_ERROR)))
.WillOnce(DoAll(SetArgPointee<0>(provisioningIDMap),
Return(wvcdm::NO_ERROR)))
.WillOnce(DoAll(SetArgPointee<0>(maxSessionsMap),
Return(wvcdm::NO_ERROR)));
String8 stringResult;
@@ -759,6 +765,10 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
ASSERT_EQ(OK, res);
EXPECT_THAT(vectorResult, ElementsAreArray(provisioningId.data(),
provisioningId.size()));
res = plugin.getPropertyString(String8("maxNumberOfSessions"), stringResult);
ASSERT_EQ(OK, res);
EXPECT_EQ(maxSessions, stringResult.string());
}
TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {

View File

@@ -274,6 +274,7 @@ typedef enum RSA_Padding_Scheme {
#define OEMCrypto_DeleteUsageTable _oecc34
#define OEMCrypto_LoadKeys _oecc35
#define OEMCrypto_GenerateRSASignature _oecc36
#define OEMCrypto_GetMaxNumberOfSessions _oecc37
/*
* OEMCrypto_Initialize
@@ -1993,6 +1994,30 @@ OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session,
*/
OEMCryptoResult OEMCrypto_DeleteUsageTable();
/*
* OEMCRYPTO_GetMaxNumberOfSessions()
*
* Description:
* Returns the maximum number of concurrent OEMCrypto sessions supported by
* the device. The CDM and OEMCrypto consumers can query this value so they
* can use resources more effectively.
*
* Parameters:
* maximum (out) - the maximum number of OEMCrypto sessions supported by the
* device.
*
* Threading:
* This function may be called simultaneously with any other functions.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_UNKNOWN_FAILURE
*
* Version:
* This method is added in API version 10.
*/
OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t *max);
#ifdef __cplusplus
}
#endif

View File

@@ -50,6 +50,7 @@ namespace wvoec3 {
#define Level3_ReportUsage _lcc32
#define Level3_DeleteUsageEntry _lcc33
#define Level3_DeleteUsageTable _lcc34
#define Level3_GetMaxNumberOfSessions _lcc37
extern "C" {
@@ -185,6 +186,7 @@ OEMCryptoResult Level3_DeleteUsageEntry(OEMCrypto_SESSION session,
const uint8_t *signature,
size_t signature_length);
OEMCryptoResult Level3_DeleteUsageTable();
OEMCryptoResult Level3_GetMaxNumberOfSessions(size_t *maximum);
};
}
#endif // LEVEL3_OEMCRYPTO_H_

View File

@@ -1291,4 +1291,15 @@ OEMCryptoResult OEMCrypto_DeleteUsageTable() {
return OEMCrypto_SUCCESS;
}
extern "C"
OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t *maximum) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(%p)\n", maximum);
}
if (maximum == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const size_t kMaxSupportedOEMCryptoSessions = 64;
*maximum = kMaxSupportedOEMCryptoSessions;
return OEMCrypto_SUCCESS;
}
} // namespace wvoec_mock

View File

@@ -1597,7 +1597,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
uint32_t version = OEMCrypto_APIVersion();
cout << " OEMCrypto API version is " << version << endl;
ASSERT_LE(8, version);
ASSERT_GE(9, version);
ASSERT_GE(10, version);
}
TEST_F(OEMCryptoClientTest, NormalGetKeyData) {
@@ -1650,6 +1650,13 @@ TEST_F(OEMCryptoClientTest, CheckHDCPCapability) {
HDCPCapabilityAsString(maximum));
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfOEMCryptoSessions) {
size_t maximum;
OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
printf(" Max Number of Sessions: %zu.\n", maximum);
}
TEST_F(OEMCryptoClientTest, KeyboxValid) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
}
@@ -1732,19 +1739,23 @@ TEST_F(OEMCryptoClientTest, TwoSessionsOpenClose) {
ASSERT_FALSE(s2.isOpen());
}
TEST_F(OEMCryptoClientTest, EightSessionsOpenClose) {
Session s[8];
for (int i = 0; i < 8; i++) {
TEST_F(OEMCryptoClientTest, MaxSessionsOpenClose) {
size_t max_sessions;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetMaxNumberOfSessions(&max_sessions));
ASSERT_GT(max_sessions, 0);
vector<Session> s(max_sessions);
for (int i = 0; i < s.size(); i++) {
s[i].open();
ASSERT_EQ(OEMCrypto_SUCCESS, s[i].getStatus());
ASSERT_TRUE(s[i].isOpen());
}
for (int i = 0; i < 8; i++) {
for (int i = 0; i < s.size(); i++) {
s[i].close();
ASSERT_EQ(OEMCrypto_SUCCESS, s[i].getStatus());
ASSERT_FALSE(s[i].isOpen());
}
}
// TODO(kqyang): Add more tests exercising multiple sessions.
TEST_F(OEMCryptoClientTest, GenerateNonce) {
Session s;