Implement MediaDrm offline license support in Widevine hidl service.
Merged from http://go/wvgerrit/69723. The new APIs are getOfflineLicenseIds, getOfflineLicenseState and removeOfflineLicense. These methods are currently stubbed out in Widevine hidl service. This CL completes the implementation. Test: unit tests - libwvdrmdrmplugin_hidl_test Test: GTS --test com.google.android.media.gts.MediaDrmTest#testWidevineApi29 bug: 117570686 Change-Id: I96ffb75f453e36e931effefd3664b5faa8d69d30
This commit is contained in:
@@ -212,6 +212,17 @@ class CdmEngine {
|
|||||||
CdmSecurityLevel security_level,
|
CdmSecurityLevel security_level,
|
||||||
const std::string& key_set_id);
|
const std::string& key_set_id);
|
||||||
|
|
||||||
|
// Get offline license status: active, release or unknown
|
||||||
|
virtual CdmResponseType GetOfflineLicenseState(
|
||||||
|
const std::string& key_set_id,
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
CdmOfflineLicenseState* license_state);
|
||||||
|
|
||||||
|
// Remove offline license with the given key_set_id
|
||||||
|
virtual CdmResponseType RemoveOfflineLicense(
|
||||||
|
const std::string& key_set_id,
|
||||||
|
CdmSecurityLevel security_level);
|
||||||
|
|
||||||
// Usage related methods for streaming licenses
|
// Usage related methods for streaming licenses
|
||||||
// Retrieve a random usage info from the list of all usage infos for this app
|
// Retrieve a random usage info from the list of all usage infos for this app
|
||||||
// id.
|
// id.
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ class CdmSession {
|
|||||||
const std::string& signature);
|
const std::string& signature);
|
||||||
|
|
||||||
virtual CdmResponseType SetDecryptHash(uint32_t frame_number,
|
virtual CdmResponseType SetDecryptHash(uint32_t frame_number,
|
||||||
const std::string& hash);
|
const std::string& hash);
|
||||||
|
|
||||||
virtual CdmResponseType GetDecryptHashError(std::string* hash_error_string);
|
virtual CdmResponseType GetDecryptHashError(std::string* hash_error_string);
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ class DeviceFiles {
|
|||||||
const CdmUsageEntry& usage_entry,
|
const CdmUsageEntry& usage_entry,
|
||||||
uint32_t usage_entry_number,
|
uint32_t usage_entry_number,
|
||||||
ResponseType* result);
|
ResponseType* result);
|
||||||
|
|
||||||
virtual bool RetrieveLicense(
|
virtual bool RetrieveLicense(
|
||||||
const std::string& key_set_id, LicenseState* state,
|
const std::string& key_set_id, LicenseState* state,
|
||||||
CdmInitData* pssh_data, CdmKeyMessage* key_request,
|
CdmInitData* pssh_data, CdmKeyMessage* key_request,
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ enum CdmKeyRequestType {
|
|||||||
kKeyRequestTypeRelease,
|
kKeyRequestTypeRelease,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CdmOfflineLicenseState {
|
||||||
|
kLicenseStateActive,
|
||||||
|
kLicenseStateReleasing,
|
||||||
|
kLicenseStateUnknown,
|
||||||
|
};
|
||||||
|
|
||||||
enum CdmResponseType {
|
enum CdmResponseType {
|
||||||
NO_ERROR = 0,
|
NO_ERROR = 0,
|
||||||
UNKNOWN_ERROR = 1,
|
UNKNOWN_ERROR = 1,
|
||||||
@@ -355,6 +361,11 @@ enum CdmResponseType {
|
|||||||
INVALID_LICENSE_TYPE_2 = 310,
|
INVALID_LICENSE_TYPE_2 = 310,
|
||||||
SIGNATURE_NOT_FOUND_2 = 311,
|
SIGNATURE_NOT_FOUND_2 = 311,
|
||||||
SESSION_KEYS_NOT_FOUND_2 = 312,
|
SESSION_KEYS_NOT_FOUND_2 = 312,
|
||||||
|
GET_OFFLINE_LICENSE_STATE_ERROR_1 = 313,
|
||||||
|
GET_OFFLINE_LICENSE_STATE_ERROR_2 = 314,
|
||||||
|
REMOVE_OFFLINE_LICENSE_ERROR_1 = 315,
|
||||||
|
REMOVE_OFFLINE_LICENSE_ERROR_2 = 316,
|
||||||
|
SESSION_NOT_FOUND_21 = 317,
|
||||||
// Don't forget to add new values to ../test/test_printers.cpp.
|
// Don't forget to add new values to ../test/test_printers.cpp.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ namespace {
|
|||||||
const uint64_t kReleaseSessionTimeToLive = 60; // seconds
|
const uint64_t kReleaseSessionTimeToLive = 60; // seconds
|
||||||
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
|
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
|
||||||
const size_t kUsageReportsPerRequest = 1;
|
const size_t kUsageReportsPerRequest = 1;
|
||||||
|
|
||||||
|
wvcdm::CdmOfflineLicenseState MapDeviceFilesLicenseState(
|
||||||
|
wvcdm::DeviceFiles::LicenseState state) {
|
||||||
|
switch (state) {
|
||||||
|
case wvcdm::DeviceFiles::LicenseState::kLicenseStateActive:
|
||||||
|
return wvcdm::kLicenseStateActive;
|
||||||
|
case wvcdm::DeviceFiles::LicenseState::kLicenseStateReleasing:
|
||||||
|
return wvcdm::kLicenseStateReleasing;
|
||||||
|
default:
|
||||||
|
return wvcdm::kLicenseStateUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
@@ -1100,6 +1112,98 @@ CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CdmResponseType CdmEngine::GetOfflineLicenseState(
|
||||||
|
const CdmKeySetId &key_set_id,
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
CdmOfflineLicenseState* license_state) {
|
||||||
|
DeviceFiles handle(file_system_);
|
||||||
|
if (!handle.Init(security_level)) {
|
||||||
|
LOGE("CdmEngine::GetOfflineLicenseState: cannot initialize device files");
|
||||||
|
return GET_OFFLINE_LICENSE_STATE_ERROR_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceFiles::LicenseState state;
|
||||||
|
|
||||||
|
// Dummy arguments to make the RetrieveLicense call,
|
||||||
|
// do not care about the return value except for license state.
|
||||||
|
CdmAppParameterMap app_parameters;
|
||||||
|
CdmKeyMessage key_request;
|
||||||
|
CdmKeyResponse key_response;
|
||||||
|
CdmInitData offline_init_data;
|
||||||
|
CdmKeyMessage offline_key_renewal_request;
|
||||||
|
CdmKeyResponse offline_key_renewal_response;
|
||||||
|
CdmUsageEntry usage_entry;
|
||||||
|
int64_t grace_period_end_time;
|
||||||
|
int64_t last_playback_time;
|
||||||
|
std::string offline_release_server_url;
|
||||||
|
int64_t playback_start_time;
|
||||||
|
uint32_t usage_entry_number;
|
||||||
|
DeviceFiles::ResponseType sub_error_code = DeviceFiles::kNoError;
|
||||||
|
|
||||||
|
if (handle.RetrieveLicense(key_set_id, &state, &offline_init_data,
|
||||||
|
&key_request, &key_response,
|
||||||
|
&offline_key_renewal_request, &offline_key_renewal_response,
|
||||||
|
&offline_release_server_url,
|
||||||
|
&playback_start_time, &last_playback_time, &grace_period_end_time,
|
||||||
|
&app_parameters, &usage_entry, &usage_entry_number,
|
||||||
|
&sub_error_code)) {
|
||||||
|
*license_state = MapDeviceFilesLicenseState(state);
|
||||||
|
} else {
|
||||||
|
LOGE("CdmEngine::GetOfflineLicenseState:: failed to retrieve license state "
|
||||||
|
"key set id = %s",
|
||||||
|
key_set_id.c_str());
|
||||||
|
return GET_OFFLINE_LICENSE_STATE_ERROR_2;
|
||||||
|
}
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType CdmEngine::RemoveOfflineLicense(
|
||||||
|
const CdmKeySetId &key_set_id,
|
||||||
|
CdmSecurityLevel security_level) {
|
||||||
|
|
||||||
|
UsagePropertySet property_set;
|
||||||
|
property_set.set_security_level(
|
||||||
|
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||||
|
DeviceFiles handle(file_system_);
|
||||||
|
CdmResponseType sts = OpenKeySetSession(key_set_id,
|
||||||
|
&property_set, nullptr /* event listener */);
|
||||||
|
if (sts != NO_ERROR) {
|
||||||
|
if (!handle.Init(security_level)) {
|
||||||
|
LOGE("CdmEngine::RemoveOfflineLicense: cannot initialize device files");
|
||||||
|
}
|
||||||
|
handle.DeleteLicense(key_set_id);
|
||||||
|
return REMOVE_OFFLINE_LICENSE_ERROR_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmSessionId session_id;
|
||||||
|
CdmAppParameterMap dummy_app_params;
|
||||||
|
InitializationData dummy_init_data("", "", "");
|
||||||
|
CdmKeyRequest key_request;
|
||||||
|
// Calling with no session_id is okay
|
||||||
|
sts = GenerateKeyRequest(session_id, key_set_id, dummy_init_data,
|
||||||
|
kLicenseTypeRelease, dummy_app_params, &key_request);
|
||||||
|
if (sts == KEY_MESSAGE) {
|
||||||
|
std::unique_lock<std::mutex> lock(release_key_sets_lock_);
|
||||||
|
CdmReleaseKeySetMap::iterator iter = release_key_sets_.find(key_set_id);
|
||||||
|
if (iter == release_key_sets_.end()) {
|
||||||
|
LOGE("CdmEngine::RemoveOfflineLicense: key set id not found = %s",
|
||||||
|
key_set_id.c_str());
|
||||||
|
sts = REMOVE_OFFLINE_LICENSE_ERROR_2;
|
||||||
|
} else {
|
||||||
|
session_id = iter->second.first;
|
||||||
|
sts = RemoveLicense(session_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sts != NO_ERROR) {
|
||||||
|
LOGE("CdmEngine: GenerateKeyRequest error=%d", sts);
|
||||||
|
handle.DeleteLicense(key_set_id);
|
||||||
|
}
|
||||||
|
CloseKeySetSession(key_set_id);
|
||||||
|
|
||||||
|
return sts;
|
||||||
|
}
|
||||||
|
|
||||||
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||||
const CdmSecureStopId& ssid,
|
const CdmSecureStopId& ssid,
|
||||||
CdmUsageInfo* usage_info) {
|
CdmUsageInfo* usage_info) {
|
||||||
|
|||||||
@@ -154,6 +154,12 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
|||||||
case GET_LICENSE_ERROR:
|
case GET_LICENSE_ERROR:
|
||||||
*os << "GET_LICENSE_ERROR";
|
*os << "GET_LICENSE_ERROR";
|
||||||
break;
|
break;
|
||||||
|
case GET_OFFLINE_LICENSE_STATE_ERROR_1:
|
||||||
|
*os << "GET_OFFLINE_LICENSE_STATE_ERROR_1";
|
||||||
|
break;
|
||||||
|
case GET_OFFLINE_LICENSE_STATE_ERROR_2:
|
||||||
|
*os << "GET_OFFLINE_LICENSE_STATE_ERROR_2";
|
||||||
|
break;
|
||||||
case GET_RELEASED_LICENSE_ERROR:
|
case GET_RELEASED_LICENSE_ERROR:
|
||||||
*os << "GET_RELEASED_LICENSE_ERROR";
|
*os << "GET_RELEASED_LICENSE_ERROR";
|
||||||
break;
|
break;
|
||||||
@@ -784,6 +790,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
|||||||
case SESSION_NOT_FOUND_20:
|
case SESSION_NOT_FOUND_20:
|
||||||
*os << "SESSION_NOT_FOUND_20";
|
*os << "SESSION_NOT_FOUND_20";
|
||||||
break;
|
break;
|
||||||
|
case SESSION_NOT_FOUND_21:
|
||||||
|
*os << "SESSION_NOT_FOUND_21";
|
||||||
|
break;
|
||||||
case INVALID_DECRYPT_HASH_FORMAT:
|
case INVALID_DECRYPT_HASH_FORMAT:
|
||||||
*os << "INVALID_DECRYPT_HASH_FORMAT";
|
*os << "INVALID_DECRYPT_HASH_FORMAT";
|
||||||
break;
|
break;
|
||||||
@@ -825,6 +834,11 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
|||||||
break;
|
break;
|
||||||
case SESSION_KEYS_NOT_FOUND_2:
|
case SESSION_KEYS_NOT_FOUND_2:
|
||||||
*os << "SESSION_KEYS_NOT_FOUND_2";
|
*os << "SESSION_KEYS_NOT_FOUND_2";
|
||||||
|
case REMOVE_OFFLINE_LICENSE_ERROR_1:
|
||||||
|
*os << "REMOVE_OFFLINE_LICENSE_ERROR_1";
|
||||||
|
break;
|
||||||
|
case REMOVE_OFFLINE_LICENSE_ERROR_2:
|
||||||
|
*os << "REMOVE_OFFLINE_LICENSE_ERROR_2";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*os << "Unknown CdmResponseType";
|
*os << "Unknown CdmResponseType";
|
||||||
|
|||||||
@@ -147,6 +147,26 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
|
|||||||
virtual CdmResponseType GetDecryptHashError(const CdmSessionId& session_id,
|
virtual CdmResponseType GetDecryptHashError(const CdmSessionId& session_id,
|
||||||
std::string* hash_error_string);
|
std::string* hash_error_string);
|
||||||
|
|
||||||
|
// Return the list of key_set_ids stored on the current (origin-specific)
|
||||||
|
// file system.
|
||||||
|
virtual CdmResponseType ListStoredLicenses(
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
const CdmIdentifier& identifier,
|
||||||
|
std::vector<CdmKeySetId>* key_set_ids);
|
||||||
|
|
||||||
|
// Retrieve offline license state using key_set_id.
|
||||||
|
virtual CdmResponseType GetOfflineLicenseState(
|
||||||
|
const CdmKeySetId& key_set_id,
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
const CdmIdentifier& identifier,
|
||||||
|
CdmOfflineLicenseState* licenseState);
|
||||||
|
|
||||||
|
// Remove offline license using key_set_id.
|
||||||
|
virtual CdmResponseType RemoveOfflineLicense(
|
||||||
|
const CdmKeySetId& key_set_id,
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
const CdmIdentifier& identifier);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CdmInfo {
|
struct CdmInfo {
|
||||||
CdmInfo();
|
CdmInfo();
|
||||||
|
|||||||
@@ -525,4 +525,32 @@ uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {
|
|||||||
return ++next_session_sharing_id;
|
return ++next_session_sharing_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CdmResponseType WvContentDecryptionModule::ListStoredLicenses(
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
const CdmIdentifier& identifier,
|
||||||
|
std::vector<CdmKeySetId>* key_set_ids) {
|
||||||
|
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||||
|
return cdm_engine->ListStoredLicenses(
|
||||||
|
security_level, key_set_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType WvContentDecryptionModule::GetOfflineLicenseState(
|
||||||
|
const CdmKeySetId& key_set_id,
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
const CdmIdentifier& identifier,
|
||||||
|
CdmOfflineLicenseState* license_state) {
|
||||||
|
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||||
|
return cdm_engine->GetOfflineLicenseState(
|
||||||
|
key_set_id, security_level, license_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType WvContentDecryptionModule::RemoveOfflineLicense(
|
||||||
|
const CdmKeySetId& key_set_id,
|
||||||
|
CdmSecurityLevel security_level,
|
||||||
|
const CdmIdentifier& identifier) {
|
||||||
|
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||||
|
return cdm_engine->RemoveOfflineLicense(
|
||||||
|
key_set_id, security_level);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
|
|||||||
case wvcdm::SESSION_NOT_FOUND_18:
|
case wvcdm::SESSION_NOT_FOUND_18:
|
||||||
case wvcdm::SESSION_NOT_FOUND_19:
|
case wvcdm::SESSION_NOT_FOUND_19:
|
||||||
case wvcdm::SESSION_NOT_FOUND_20:
|
case wvcdm::SESSION_NOT_FOUND_20:
|
||||||
|
case wvcdm::SESSION_NOT_FOUND_21:
|
||||||
return android::ERROR_DRM_SESSION_NOT_OPENED;
|
return android::ERROR_DRM_SESSION_NOT_OPENED;
|
||||||
case wvcdm::SESSION_KEYS_NOT_FOUND:
|
case wvcdm::SESSION_KEYS_NOT_FOUND:
|
||||||
return kSessionKeysNotFound;
|
return kSessionKeysNotFound;
|
||||||
@@ -557,6 +558,15 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
|
|||||||
return kSignatureNotFound2;
|
return kSignatureNotFound2;
|
||||||
case wvcdm::SESSION_KEYS_NOT_FOUND_2:
|
case wvcdm::SESSION_KEYS_NOT_FOUND_2:
|
||||||
return kSessionKeysNotFound2;
|
return kSessionKeysNotFound2;
|
||||||
|
|
||||||
|
// This error is only returned in API 29 by the hidl service.
|
||||||
|
// It should never be used in the legacy plugin.
|
||||||
|
// It is mapped here to clear the compiler warning.
|
||||||
|
case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_1:
|
||||||
|
case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_2:
|
||||||
|
case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_1:
|
||||||
|
case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_2:
|
||||||
|
return android::ERROR_DRM_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return here instead of as a default case so that the compiler will warn
|
// Return here instead of as a default case so that the compiler will warn
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
|
|||||||
case wvcdm::SESSION_NOT_FOUND_18:
|
case wvcdm::SESSION_NOT_FOUND_18:
|
||||||
case wvcdm::SESSION_NOT_FOUND_19:
|
case wvcdm::SESSION_NOT_FOUND_19:
|
||||||
case wvcdm::SESSION_NOT_FOUND_20:
|
case wvcdm::SESSION_NOT_FOUND_20:
|
||||||
|
case wvcdm::SESSION_NOT_FOUND_21:
|
||||||
return Status::ERROR_DRM_SESSION_NOT_OPENED;
|
return Status::ERROR_DRM_SESSION_NOT_OPENED;
|
||||||
|
|
||||||
case wvcdm::DECRYPT_ERROR:
|
case wvcdm::DECRYPT_ERROR:
|
||||||
@@ -321,6 +322,10 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
|
|||||||
case wvcdm::INVALID_LICENSE_TYPE_2:
|
case wvcdm::INVALID_LICENSE_TYPE_2:
|
||||||
case wvcdm::SIGNATURE_NOT_FOUND_2:
|
case wvcdm::SIGNATURE_NOT_FOUND_2:
|
||||||
case wvcdm::SESSION_KEYS_NOT_FOUND_2:
|
case wvcdm::SESSION_KEYS_NOT_FOUND_2:
|
||||||
|
case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_1:
|
||||||
|
case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_2:
|
||||||
|
case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_1:
|
||||||
|
case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_2:
|
||||||
ALOGW("Returns UNKNOWN error for legacy status: %d", res);
|
ALOGW("Returns UNKNOWN error for legacy status: %d", res);
|
||||||
return Status::ERROR_DRM_UNKNOWN;
|
return Status::ERROR_DRM_UNKNOWN;
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ using wvcdm::CdmProvisioningRequest;
|
|||||||
using wvcdm::CdmProvisioningResponse;
|
using wvcdm::CdmProvisioningResponse;
|
||||||
using wvcdm::CdmQueryMap;
|
using wvcdm::CdmQueryMap;
|
||||||
using wvcdm::CdmSecureStopId;
|
using wvcdm::CdmSecureStopId;
|
||||||
|
using wvcdm::CdmSecurityLevel;
|
||||||
using wvcdm::CdmUsageInfo;
|
using wvcdm::CdmUsageInfo;
|
||||||
using wvcdm::CdmUsageInfoReleaseMessage;
|
using wvcdm::CdmUsageInfoReleaseMessage;
|
||||||
using wvcdm::KeyId;
|
using wvcdm::KeyId;
|
||||||
@@ -132,7 +133,7 @@ KeyStatusType ConvertFromCdmKeyStatus(CdmKeyStatus keyStatus) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HdcpLevel mapHdcpLevel(const std::string level) {
|
HdcpLevel mapHdcpLevel(const std::string& level) {
|
||||||
if (level == wvcdm::QUERY_VALUE_HDCP_V1)
|
if (level == wvcdm::QUERY_VALUE_HDCP_V1)
|
||||||
return HdcpLevel::HDCP_V1;
|
return HdcpLevel::HDCP_V1;
|
||||||
else if (level == wvcdm::QUERY_VALUE_HDCP_V2_0)
|
else if (level == wvcdm::QUERY_VALUE_HDCP_V2_0)
|
||||||
@@ -1048,20 +1049,91 @@ Return<void> WVDrmPlugin::getSecurityLevel(
|
|||||||
|
|
||||||
Return<void> WVDrmPlugin::getOfflineLicenseKeySetIds(
|
Return<void> WVDrmPlugin::getOfflineLicenseKeySetIds(
|
||||||
getOfflineLicenseKeySetIds_cb _hidl_cb) {
|
getOfflineLicenseKeySetIds_cb _hidl_cb) {
|
||||||
std::vector<KeySetId> keySetIds;
|
std::vector<std::vector<uint8_t> > keySetIds;
|
||||||
|
std::vector<KeySetId> keySetIdsVec;
|
||||||
|
|
||||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, keySetIds);
|
CdmIdentifier identifier;
|
||||||
|
Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||||
|
if (status != Status::OK) {
|
||||||
|
_hidl_cb(status, toHidlVec(keySetIdsVec));
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CdmSecurityLevel> levels = {
|
||||||
|
wvcdm::kSecurityLevelL1, wvcdm::kSecurityLevelL3 };
|
||||||
|
|
||||||
|
CdmResponseType res = wvcdm::UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
for (auto level : levels) {
|
||||||
|
std::vector<CdmKeySetId> cdmKeySetIds;
|
||||||
|
res = mCDM->ListStoredLicenses(level, identifier, &cdmKeySetIds);
|
||||||
|
|
||||||
|
if (isCdmResponseTypeSuccess(res)) {
|
||||||
|
keySetIds.clear();
|
||||||
|
for (auto id : cdmKeySetIds) {
|
||||||
|
keySetIds.push_back(StrToVector(id));
|
||||||
|
}
|
||||||
|
for (auto id : keySetIds) {
|
||||||
|
keySetIdsVec.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_hidl_cb(mapCdmResponseType(res), toHidlVec(keySetIdsVec));
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
Return<void> WVDrmPlugin::getOfflineLicenseState(const KeySetId &keySetId,
|
Return<void> WVDrmPlugin::getOfflineLicenseState(const KeySetId &keySetId,
|
||||||
getOfflineLicenseState_cb _hidl_cb) {
|
getOfflineLicenseState_cb _hidl_cb) {
|
||||||
|
OfflineLicenseState licenseState = OfflineLicenseState::UNKNOWN;
|
||||||
|
|
||||||
if (!keySetId.size()) {
|
if (!keySetId.size()) {
|
||||||
_hidl_cb(Status::BAD_VALUE, OfflineLicenseState::UNKNOWN);
|
_hidl_cb(Status::BAD_VALUE, licenseState);
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, OfflineLicenseState::UNKNOWN);
|
CdmIdentifier identifier;
|
||||||
|
Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||||
|
if (status != Status::OK) {
|
||||||
|
_hidl_cb(status, licenseState);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType res = wvcdm::UNKNOWN_ERROR;
|
||||||
|
CdmKeySetId keySetIdStr(keySetId.begin(), keySetId.end());
|
||||||
|
|
||||||
|
wvcdm::CdmOfflineLicenseState state = wvcdm::kLicenseStateUnknown;
|
||||||
|
res = mCDM->GetOfflineLicenseState(
|
||||||
|
keySetIdStr,
|
||||||
|
wvcdm::kSecurityLevelL1,
|
||||||
|
identifier,
|
||||||
|
&state);
|
||||||
|
if (!isCdmResponseTypeSuccess(res)) {
|
||||||
|
// try L3
|
||||||
|
res = mCDM->GetOfflineLicenseState(
|
||||||
|
keySetIdStr,
|
||||||
|
wvcdm::kSecurityLevelL3,
|
||||||
|
identifier,
|
||||||
|
&state);
|
||||||
|
if (!isCdmResponseTypeSuccess(res)) {
|
||||||
|
_hidl_cb(Status::BAD_VALUE, licenseState);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(state) {
|
||||||
|
case wvcdm::kLicenseStateActive:
|
||||||
|
licenseState = OfflineLicenseState::USABLE;
|
||||||
|
break;
|
||||||
|
case wvcdm::kLicenseStateReleasing:
|
||||||
|
licenseState = OfflineLicenseState::INACTIVE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
licenseState = OfflineLicenseState::UNKNOWN;
|
||||||
|
ALOGE("Return unknown offline license state for %s", keySetIdStr.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_hidl_cb(mapCdmResponseType(res), licenseState);
|
||||||
return Void();
|
return Void();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1070,7 +1142,31 @@ Return<Status> WVDrmPlugin::removeOfflineLicense(const KeySetId &keySetId) {
|
|||||||
return Status::BAD_VALUE;
|
return Status::BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status::ERROR_DRM_CANNOT_HANDLE;
|
CdmIdentifier identifier;
|
||||||
|
Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier);
|
||||||
|
if (status != Status::OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType res = wvcdm::UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
res = mCDM->RemoveOfflineLicense(
|
||||||
|
std::string(keySetId.begin(), keySetId.end()),
|
||||||
|
wvcdm::kSecurityLevelL1,
|
||||||
|
identifier);
|
||||||
|
if (!isCdmResponseTypeSuccess(res)) {
|
||||||
|
CdmResponseType res = mCDM->RemoveOfflineLicense(
|
||||||
|
std::string(keySetId.begin(), keySetId.end()),
|
||||||
|
wvcdm::kSecurityLevelL3,
|
||||||
|
identifier);
|
||||||
|
if (isCdmResponseTypeSuccess(res)) {
|
||||||
|
status = Status::OK;
|
||||||
|
} else {
|
||||||
|
status = Status::ERROR_DRM_INVALID_STATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Return<void> WVDrmPlugin::getPropertyString(const hidl_string& propertyName,
|
Return<void> WVDrmPlugin::getPropertyString(const hidl_string& propertyName,
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ using wvcdm::CdmKeyRequest;
|
|||||||
using wvcdm::CdmKeySetId;
|
using wvcdm::CdmKeySetId;
|
||||||
using wvcdm::CdmKeySystem;
|
using wvcdm::CdmKeySystem;
|
||||||
using wvcdm::CdmLicenseType;
|
using wvcdm::CdmLicenseType;
|
||||||
|
using wvcdm::CdmOfflineLicenseState;
|
||||||
using wvcdm::CdmProvisioningRequest;
|
using wvcdm::CdmProvisioningRequest;
|
||||||
using wvcdm::CdmProvisioningResponse;
|
using wvcdm::CdmProvisioningResponse;
|
||||||
using wvcdm::CdmQueryMap;
|
using wvcdm::CdmQueryMap;
|
||||||
@@ -159,7 +160,8 @@ class MockCDM : public WvContentDecryptionModule {
|
|||||||
MOCK_METHOD2(RestoreKey, CdmResponseType(const CdmSessionId&,
|
MOCK_METHOD2(RestoreKey, CdmResponseType(const CdmSessionId&,
|
||||||
const CdmKeySetId&));
|
const CdmKeySetId&));
|
||||||
|
|
||||||
MOCK_METHOD3(QueryStatus, CdmResponseType(wvcdm::SecurityLevel, const std::string&,
|
MOCK_METHOD3(QueryStatus, CdmResponseType(wvcdm::SecurityLevel,
|
||||||
|
const std::string&,
|
||||||
std::string*));
|
std::string*));
|
||||||
|
|
||||||
MOCK_METHOD2(QueryKeyStatus, CdmResponseType(const CdmSessionId&,
|
MOCK_METHOD2(QueryKeyStatus, CdmResponseType(const CdmSessionId&,
|
||||||
@@ -202,7 +204,24 @@ class MockCDM : public WvContentDecryptionModule {
|
|||||||
MOCK_METHOD2(GetMetrics, CdmResponseType(const CdmIdentifier&,
|
MOCK_METHOD2(GetMetrics, CdmResponseType(const CdmIdentifier&,
|
||||||
drm_metrics::WvCdmMetrics*));
|
drm_metrics::WvCdmMetrics*));
|
||||||
|
|
||||||
MOCK_METHOD2(GetDecryptHashError, CdmResponseType(const CdmSessionId&, std::string*));
|
MOCK_METHOD2(GetDecryptHashError,
|
||||||
|
CdmResponseType(const CdmSessionId&, std::string*));
|
||||||
|
|
||||||
|
MOCK_METHOD3(ListStoredLicenses,
|
||||||
|
CdmResponseType(CdmSecurityLevel,
|
||||||
|
const CdmIdentifier&,
|
||||||
|
std::vector<std::string>*));
|
||||||
|
|
||||||
|
MOCK_METHOD4(GetOfflineLicenseState,
|
||||||
|
CdmResponseType(const std::string&,
|
||||||
|
CdmSecurityLevel,
|
||||||
|
const CdmIdentifier&,
|
||||||
|
CdmOfflineLicenseState*));
|
||||||
|
|
||||||
|
MOCK_METHOD3(RemoveOfflineLicense,
|
||||||
|
CdmResponseType(const std::string&,
|
||||||
|
CdmSecurityLevel,
|
||||||
|
const CdmIdentifier&));
|
||||||
};
|
};
|
||||||
|
|
||||||
class MockCrypto : public WVGenericCryptoInterface {
|
class MockCrypto : public WVGenericCryptoInterface {
|
||||||
@@ -260,8 +279,11 @@ MATCHER_P(HasOrigin, origin, "") {
|
|||||||
|
|
||||||
class WVDrmPluginTest : public Test {
|
class WVDrmPluginTest : public Test {
|
||||||
protected:
|
protected:
|
||||||
|
static const uint32_t kKeySetIdSize = 32;
|
||||||
static const uint32_t kSessionIdSize = 16;
|
static const uint32_t kSessionIdSize = 16;
|
||||||
|
uint8_t keySetIdRaw[kKeySetIdSize];
|
||||||
uint8_t sessionIdRaw[kSessionIdSize];
|
uint8_t sessionIdRaw[kSessionIdSize];
|
||||||
|
std::vector<uint8_t> keySetId;
|
||||||
std::vector<uint8_t> sessionId;
|
std::vector<uint8_t> sessionId;
|
||||||
CdmSessionId cdmSessionId;
|
CdmSessionId cdmSessionId;
|
||||||
|
|
||||||
@@ -269,12 +291,19 @@ class WVDrmPluginTest : public Test {
|
|||||||
// Fill the session ID
|
// Fill the session ID
|
||||||
FILE* fp = fopen("/dev/urandom", "r");
|
FILE* fp = fopen("/dev/urandom", "r");
|
||||||
fread(sessionIdRaw, sizeof(uint8_t), kSessionIdSize, fp);
|
fread(sessionIdRaw, sizeof(uint8_t), kSessionIdSize, fp);
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
memcpy(sessionIdRaw, SESSION_ID_PREFIX, sizeof(SESSION_ID_PREFIX) - 1);
|
memcpy(sessionIdRaw, SESSION_ID_PREFIX, sizeof(SESSION_ID_PREFIX) - 1);
|
||||||
sessionId.assign(sessionIdRaw, sessionIdRaw + kSessionIdSize);
|
sessionId.assign(sessionIdRaw, sessionIdRaw + kSessionIdSize);
|
||||||
cdmSessionId.assign(sessionId.begin(), sessionId.end());
|
cdmSessionId.assign(sessionId.begin(), sessionId.end());
|
||||||
|
|
||||||
|
fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX));
|
||||||
|
CdmKeySetId cdmKeySetId(reinterpret_cast<char*>(keySetIdRaw),
|
||||||
|
kKeySetIdSize);
|
||||||
|
keySetId.assign(keySetIdRaw, keySetIdRaw + kKeySetIdSize);
|
||||||
|
|
||||||
// Set default return values for gMock
|
// Set default return values for gMock
|
||||||
DefaultValue<CdmResponseType>::Set(wvcdm::NO_ERROR);
|
DefaultValue<CdmResponseType>::Set(wvcdm::NO_ERROR);
|
||||||
DefaultValue<OEMCryptoResult>::Set(OEMCrypto_SUCCESS);
|
DefaultValue<OEMCryptoResult>::Set(OEMCrypto_SUCCESS);
|
||||||
@@ -728,15 +757,6 @@ TEST_F(WVDrmPluginTest, RestoresKeys) {
|
|||||||
StrictMock<MockCrypto> crypto;
|
StrictMock<MockCrypto> crypto;
|
||||||
std::string appPackageName;
|
std::string appPackageName;
|
||||||
|
|
||||||
static const size_t kKeySetIdSize = 32;
|
|
||||||
uint8_t keySetIdRaw[kKeySetIdSize];
|
|
||||||
FILE* fp = fopen("/dev/urandom", "r");
|
|
||||||
fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
std::vector<uint8_t> keySetId;
|
|
||||||
keySetId.assign(keySetIdRaw, keySetIdRaw + kKeySetIdSize);
|
|
||||||
|
|
||||||
EXPECT_CALL(*cdm, RestoreKey(cdmSessionId,
|
EXPECT_CALL(*cdm, RestoreKey(cdmSessionId,
|
||||||
ElementsAreArray(keySetIdRaw, kKeySetIdSize)))
|
ElementsAreArray(keySetIdRaw, kKeySetIdSize)))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
@@ -1039,7 +1059,7 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
|
|||||||
.WillOnce(DoAll(SetArgPointee<2>(cdmStops),
|
.WillOnce(DoAll(SetArgPointee<2>(cdmStops),
|
||||||
testing::Return(wvcdm::NO_ERROR)));
|
testing::Return(wvcdm::NO_ERROR)));
|
||||||
|
|
||||||
std::list<std::vector<uint8_t> > stops;
|
std::vector<std::vector<uint8_t> > stops;
|
||||||
|
|
||||||
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||||
Status status = plugin.setPropertyString(hidl_string("appId"),
|
Status status = plugin.setPropertyString(hidl_string("appId"),
|
||||||
@@ -1058,17 +1078,11 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
std::list<std::vector<uint8_t> >::iterator iter = stops.begin();
|
size_t index = 0;
|
||||||
uint32_t rawIter = 0;
|
for (auto stop : stops) {
|
||||||
while (rawIter < kStopCount && iter != stops.end()) {
|
EXPECT_THAT(stop, ElementsAreArray(stopsRaw[index++], kStopSize));
|
||||||
EXPECT_THAT(*iter, ElementsAreArray(stopsRaw[rawIter], kStopSize));
|
|
||||||
|
|
||||||
++iter;
|
|
||||||
++rawIter;
|
|
||||||
}
|
}
|
||||||
// Assert that both lists are the same length
|
EXPECT_EQ(kStopCount, index);
|
||||||
EXPECT_EQ(kStopCount, rawIter);
|
|
||||||
EXPECT_EQ(stops.end(), iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WVDrmPluginTest, ReleasesAllSecureStops) {
|
TEST_F(WVDrmPluginTest, ReleasesAllSecureStops) {
|
||||||
@@ -2715,6 +2729,124 @@ TEST_F(WVDrmPluginTest, DoesNotSetDecryptHashProperties) {
|
|||||||
ASSERT_EQ(Status::OK, status);
|
ASSERT_EQ(Status::OK, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, GetOfflineLicenseIds) {
|
||||||
|
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
std::string appPackageName;
|
||||||
|
|
||||||
|
const uint32_t kLicenseCount = 5;
|
||||||
|
|
||||||
|
uint8_t mockIdsRaw[kLicenseCount * 2][kKeySetIdSize];
|
||||||
|
FILE* fp = fopen("/dev/urandom", "r");
|
||||||
|
for (uint32_t i = 0; i < kLicenseCount * 2; ++i) {
|
||||||
|
fread(mockIdsRaw[i], sizeof(uint8_t), kKeySetIdSize, fp);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
std::vector<std::string> mockIdsL1;
|
||||||
|
for (uint32_t i = 0; i < kLicenseCount; ++i) {
|
||||||
|
mockIdsL1.push_back(std::string(mockIdsRaw[i],
|
||||||
|
mockIdsRaw[i] + kKeySetIdSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> mockIdsL3;
|
||||||
|
for (uint32_t i = 0; i < kLicenseCount; ++i) {
|
||||||
|
mockIdsL3.push_back(std::string(mockIdsRaw[i+5],
|
||||||
|
mockIdsRaw[i+5] + kKeySetIdSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_CALL(*cdm,
|
||||||
|
ListStoredLicenses(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN), _))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<2>(mockIdsL1),
|
||||||
|
testing::Return(wvcdm::NO_ERROR)));
|
||||||
|
|
||||||
|
EXPECT_CALL(*cdm,
|
||||||
|
ListStoredLicenses(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN), _))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<2>(mockIdsL3),
|
||||||
|
testing::Return(wvcdm::NO_ERROR)));
|
||||||
|
|
||||||
|
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||||
|
|
||||||
|
std::vector<std::vector<uint8_t> > offlineIds;
|
||||||
|
offlineIds.clear();
|
||||||
|
plugin.getOfflineLicenseKeySetIds(
|
||||||
|
[&](Status status, hidl_vec<KeySetId> hKeySetIds) {
|
||||||
|
ASSERT_EQ(Status::OK, status);
|
||||||
|
|
||||||
|
std::vector<KeySetId> ids(hKeySetIds);
|
||||||
|
|
||||||
|
for (auto id : ids) {
|
||||||
|
offlineIds.push_back(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
for (auto id : offlineIds) {
|
||||||
|
EXPECT_THAT(id, ElementsAreArray(mockIdsRaw[index++], kKeySetIdSize));
|
||||||
|
}
|
||||||
|
EXPECT_EQ(kLicenseCount * 2, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, GetOfflineLicenseState) {
|
||||||
|
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
std::string appPackageName;
|
||||||
|
|
||||||
|
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1),
|
||||||
|
testing::Return(wvcdm::NO_ERROR)));
|
||||||
|
|
||||||
|
EXPECT_CALL(*cdm,
|
||||||
|
GetOfflineLicenseState(_, kSecurityLevelL1,
|
||||||
|
HasOrigin(EMPTY_ORIGIN), _))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<3>(wvcdm::kLicenseStateActive),
|
||||||
|
testing::Return(wvcdm::NO_ERROR)))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<3>(wvcdm::kLicenseStateReleasing),
|
||||||
|
testing::Return(wvcdm::NO_ERROR)))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<3>(wvcdm::kLicenseStateUnknown),
|
||||||
|
testing::Return(wvcdm::NO_ERROR)));
|
||||||
|
|
||||||
|
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||||
|
Status status = plugin.setPropertyString(
|
||||||
|
hidl_string("securityLevel"), hidl_string("L1"));
|
||||||
|
ASSERT_EQ(Status::OK, status);
|
||||||
|
|
||||||
|
plugin.getOfflineLicenseState(toHidlVec(keySetId),
|
||||||
|
[&](Status status, OfflineLicenseState hLicenseState) {
|
||||||
|
ASSERT_EQ(Status::OK, status);
|
||||||
|
ASSERT_EQ(OfflineLicenseState::USABLE, hLicenseState);
|
||||||
|
});
|
||||||
|
|
||||||
|
plugin.getOfflineLicenseState(toHidlVec(keySetId),
|
||||||
|
[&](Status status, OfflineLicenseState hLicenseState) {
|
||||||
|
ASSERT_EQ(Status::OK, status);
|
||||||
|
ASSERT_EQ(OfflineLicenseState::INACTIVE, hLicenseState);
|
||||||
|
});
|
||||||
|
|
||||||
|
plugin.getOfflineLicenseState(toHidlVec(keySetId),
|
||||||
|
[&](Status status, OfflineLicenseState hLicenseState) {
|
||||||
|
ASSERT_EQ(Status::OK, status);
|
||||||
|
ASSERT_EQ(OfflineLicenseState::UNKNOWN, hLicenseState);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, RemoveOfflineLicense) {
|
||||||
|
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
std::string appPackageName;
|
||||||
|
|
||||||
|
EXPECT_CALL(*cdm,
|
||||||
|
RemoveOfflineLicense(_, kSecurityLevelL1,
|
||||||
|
HasOrigin(EMPTY_ORIGIN)))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
||||||
|
|
||||||
|
Status status = plugin.removeOfflineLicense(toHidlVec(keySetId));
|
||||||
|
ASSERT_EQ(Status::OK, status);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace widevine
|
} // namespace widevine
|
||||||
} // namespace V1_2
|
} // namespace V1_2
|
||||||
} // namespace drm
|
} // namespace drm
|
||||||
|
|||||||
Reference in New Issue
Block a user