From a9e26bdc2b0240ed93502693f0483f0f68eef501 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Fri, 25 Jun 2021 13:18:19 -0700 Subject: [PATCH 1/3] Updated integration test to handle unlimited license durations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Merge of http://go/wvgerrit/128046 ] Test case WvCdmStreamingUsageReportTest.WvCdmStreamingUsageReportTest was failing comparing "license duration" values returned when querying for key information for licenses with unlimited "rental duration". This is due to the new license duration model used for V16 licenses. From the Widevine MediaDrm doc for "LicenseDurationRemaining": For OEMCrypto v16+ (Android 11 and later), license duration is no longer being enforced. If rental duration is set to never expire, ”9223372036854775807” (LLONG_MAX) will be returned. Similarly, the test has been updated for "playback duration" queries of the same case. Bug: 163542905 Test: cdm_extended_duration_test Change-Id: I57e0e435631a151fac45c963d865de256a773644 --- .../cdm/test/cdm_extended_duration_test.cpp | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index e1ab605f..13764cc6 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -43,6 +45,8 @@ const uint32_t kClockTolerance = 10; const uint32_t kMaxUsageTableSize = 50; const std::string kEmptyServiceCertificate; +constexpr int64_t kUnlimitedDurationValue = LLONG_MAX; + // TODO(rfrias): refactor to print out the decryption test names struct SubSampleInfo { bool retrieve_key; @@ -1438,10 +1442,29 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) { QueryKeyStatus(true, false, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + // For unlimited "rental durations", the "license duration" will + // effectively be unlimited. Remaining license duration in this + // case is represented by |kUnlimitedDurationValue| and will not + // change over time. + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); From c882bd8230bceecf27efa259a2a3293848b23a7b Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Tue, 29 Jun 2021 20:21:06 -0700 Subject: [PATCH 2/3] Correct an error reported when a license is restored and then released [ Merge of http://go/wvgerrit/128143 ] Now reports LICENSE_STATE_ERROR rather than ERROR_DRM_GENERIC_PLUGIN to make the cause of failure and suggested action more clear for app developers. Also added an additional error log. Bug: 190645000 Test: WV unit/integration tests Change-Id: Ib23ca628c590316f90f497d8fdfbab24fd644d6f --- libwvdrmengine/cdm/core/include/wv_cdm_types.h | 1 + libwvdrmengine/cdm/core/src/cdm_session.cpp | 5 +++++ libwvdrmengine/cdm/core/test/test_printers.cpp | 3 +++ libwvdrmengine/include/WVErrors.h | 3 ++- libwvdrmengine/include/mapErrors-inl.h | 2 ++ libwvdrmengine/include_hidl/mapErrors-inl.h | 2 ++ 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 08b7163c..382f54de 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -420,6 +420,7 @@ enum CdmResponseType : int32_t { CERT_PROVISIONING_RESPONSE_ERROR_9 = 365, CERT_PROVISIONING_RESPONSE_ERROR_10 = 366, CLIENT_TOKEN_NOT_SET = 367, + USAGE_ENTRY_ALREADY_LOADED = 368, // Don't forget to add new values to // * core/test/test_printers.cpp. // * android/include/mapErrors-inl.h diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 783aa6e3..33443f45 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -283,6 +283,11 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id, CdmResponseType sts = usage_table_header_->LoadEntry( crypto_session_.get(), usage_entry_, usage_entry_number_); crypto_metrics_->usage_table_header_load_entry_.Increment(sts); + if (sts == LOAD_USAGE_ENTRY_INVALID_SESSION) { + LOGE("License loaded in different session: key_set_id = %s", + IdToString(key_set_id)); + return USAGE_ENTRY_ALREADY_LOADED; + } if (sts != NO_ERROR) { LOGE("Failed to load usage entry: status = %d", static_cast(sts)); return sts; diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index cd78290c..5364eb2c 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -887,6 +887,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case USAGE_ENTRY_NUMBER_MISMATCH: *os << "USAGE_ENTRY_NUMBER_MISMATCH"; break; + case USAGE_ENTRY_ALREADY_LOADED: + *os << "USAGE_ENTRY_ALREADY_LOADED"; + break; case USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: *os << "USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE"; break; diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index 2e81e97b..23cd2bfb 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -301,10 +301,11 @@ enum { kCertProvisioningResponseError9 = ERROR_DRM_VENDOR_MIN + 316, kCertProvisioningResponseError10 = ERROR_DRM_VENDOR_MIN + 317, kClientTokenNotSet = ERROR_DRM_VENDOR_MIN + 318, + kUsageEntryAlreadyLoaded = ERROR_DRM_VENDOR_MIN + 319, // This should always follow the last error code. // The offset value should be updated each time a new error code is added. - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 318, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 319, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index ab35381c..305644ec 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -539,6 +539,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kUpdateUsageEntryUnknownError; case wvcdm::USAGE_ENTRY_NUMBER_MISMATCH: return kUsageEntryNumberMismatch; + case wvcdm::USAGE_ENTRY_ALREADY_LOADED: + return kUsageEntryAlreadyLoaded; case wvcdm::USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: return kUsageGetEntryRetrieveInvalidStorageType; case wvcdm::USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED: diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index 60e83548..bceea4d9 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -361,6 +361,7 @@ static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) { case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: case wvcdm::CLIENT_TOKEN_NOT_SET: + case wvcdm::USAGE_ENTRY_ALREADY_LOADED: ALOGW("Returns UNKNOWN error for legacy status: %d", res); return Status::ERROR_DRM_UNKNOWN; @@ -617,6 +618,7 @@ static S mapCdmResponseType(wvcdm::CdmResponseType res) { break; case wvcdm::GET_RELEASED_LICENSE_ERROR: case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3: + case wvcdm::USAGE_ENTRY_ALREADY_LOADED: err = ::drm::V1_4::Status::LICENSE_STATE_ERROR; break; case wvcdm::DEVICE_CERTIFICATE_ERROR_2: From 14bd15a08c4098a6f0f7207ba7b6c8000e24c93f Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Wed, 30 Jun 2021 10:41:07 -0700 Subject: [PATCH 3/3] PST and non PST can handle unlimited license durations. [ Merge of http://go/wvgerrit/128183 ] As was the case with WvCdmStreamingUsageReportTest.ReportTest, the following tests were also updated to handle the case where "license duration" is unlimited: - WvCdmStreamingNoPstTest.UsageTest - WvCdmStreamingPstTest.UsageTest - WvCdmOfflineUsageReportTest.UsageTest This is due to the new license duration model used for V16 licenses. Bug: 163542905 Test: cdm_extended_duration_test Change-Id: I24d3fc17fcf19129a19ed39a5c6c1ddd59ed073d --- .../cdm/test/cdm_extended_duration_test.cpp | 97 +++++++++++++++---- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 13764cc6..334b6fc9 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -1308,10 +1308,25 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) { QueryKeyStatus(true, true, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); } @@ -1375,10 +1390,25 @@ TEST_P(WvCdmStreamingPstTest, UsageTest) { QueryKeyStatus(true, false, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_); } @@ -1556,11 +1586,29 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) { QueryKeyStatus(false, true, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR( - initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue) + << "i = " << i; + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining + << ", i = " << i; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue) + << "i = " << i; + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining + << ", i = " << i; + } // Decrypt data SubSampleInfo* data = &kEncryptedOfflineClip2SubSample; @@ -1600,10 +1648,25 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) { QueryKeyStatus(false, true, &license_duration_remaining, &playback_duration_remaining); - EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, - expected_seconds_since_license_received, kClockTolerance); - EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, - expected_seconds_since_initial_playback, kClockTolerance); + if (initial_license_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining, + expected_seconds_since_license_received, kClockTolerance) + << "initial_license_duration_remaining = " + << initial_license_duration_remaining + << ", license_duration_remaining = " << license_duration_remaining; + } + + if (initial_playback_duration_remaining == kUnlimitedDurationValue) { + EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue); + } else { + EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining, + expected_seconds_since_initial_playback, kClockTolerance) + << "initial_playback_duration_remaining = " + << initial_playback_duration_remaining + << ", playback_duration_remaining = " << playback_duration_remaining; + } decryptor_->CloseSession(session_id_);