diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index ef15142b..0cb57748 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -50,7 +50,7 @@ class CdmLicense { const CdmKeyResponse& license_response, const CdmKeyResponse& license_renewal_response, int64_t playback_start_time, int64_t last_playback_time, - int64_t grace_period_end_time); + int64_t grace_period_end_time, CdmSession* cdm_session); virtual bool RestoreLicenseForRelease(const CdmKeyMessage& license_request, const CdmKeyResponse& license_response); virtual bool HasInitData() { return stored_init_data_.get(); } diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 959f17a1..ea5f61ea 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -105,6 +105,7 @@ static const std::string HLS_URI_ATTRIBUTE = "URI"; static const char EMPTY_ORIGIN[] = ""; static const char EMPTY_SPOID[] = ""; +static const char EMPTY_APP_PACKAGE_NAME[] = ""; } // namespace wvcdm #endif // WVCDM_CORE_WV_CDM_CONSTANTS_H_ diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 19b38c75..8179b1c8 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -312,6 +312,7 @@ enum CdmResponseType { PARSE_RESPONSE_ERROR_2, PARSE_RESPONSE_ERROR_3, /* 270 */ PARSE_RESPONSE_ERROR_4, + RELEASE_ALL_USAGE_INFO_ERROR_6, }; enum CdmKeyStatus { diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 4c492dea..550bf5d2 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -1135,19 +1135,32 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) { if (usage_session_->get_usage_support_type() == kUsageEntrySupport) { std::vector usage_data; - if (!handle.RetrieveUsageInfo( - DeviceFiles::GetUsageInfoFileName(app_id), - &usage_data)) { - status = RELEASE_ALL_USAGE_INFO_ERROR_4; - } else { - for (size_t k = 0; k < usage_data.size(); ++k) { - CdmResponseType status2 = - usage_session_->DeleteUsageEntry( - usage_data[k].usage_entry_number); - if (status == NO_ERROR && status2 != NO_ERROR) - status = status2; + // Retrieve all usage information but delete only one before + // refetching. This is because deleting the usage entry + // might cause other entries to be shifted and information updated. + do { + if (!handle.RetrieveUsageInfo( + DeviceFiles::GetUsageInfoFileName(app_id), + &usage_data)) { + status = RELEASE_ALL_USAGE_INFO_ERROR_4; + break; } - } + + if (usage_data.empty()) break; + + status = usage_session_->DeleteUsageEntry( + usage_data[0].usage_entry_number); + + if (status != NO_ERROR) break; + + if (!handle.DeleteUsageInfo( + DeviceFiles::GetUsageInfoFileName(app_id), + usage_data[0].provider_session_token)) { + status = RELEASE_ALL_USAGE_INFO_ERROR_6; + break; + } + } while (status == NO_ERROR && !usage_data.empty()); + std::vector provider_session_tokens; if (!handle.DeleteAllUsageInfoForApp( DeviceFiles::GetUsageInfoFileName(app_id), diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 9b188be7..18020498 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -240,7 +240,8 @@ CdmResponseType CdmSession::RestoreOfflineSession( } else { if (!license_parser_->RestoreOfflineLicense( key_request_, key_response_, offline_key_renewal_response_, - playback_start_time, last_playback_time, grace_period_end_time)) { + playback_start_time, last_playback_time, grace_period_end_time, + this)) { return RESTORE_OFFLINE_LICENSE_ERROR_2; } } @@ -685,8 +686,7 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) { } CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) { - if (usage_support_type_ != kUsageEntrySupport || - !has_provider_session_token()) { + if (usage_support_type_ != kUsageEntrySupport) { LOGE("CdmSession::DeleteUsageEntry: Unexpected usage type supported: %d", usage_support_type_); return INCORRECT_USAGE_SUPPORT_TYPE_1; @@ -885,10 +885,13 @@ CdmResponseType CdmSession::UpdateUsageTableInformation() { CdmResponseType CdmSession::UpdateUsageEntryInformation() { if (usage_support_type_ != kUsageEntrySupport || - !has_provider_session_token() && - usage_table_header_ != nullptr) { - LOGE("CdmSession::UpdateUsageEntryInformation: Unexpected usage type " - "supported: %d", usage_support_type_); + !has_provider_session_token() || + usage_table_header_ == nullptr) { + LOGE("CdmSession::UpdateUsageEntryInformation: Unexpected state, " + "usage support type: %d, PST present: %s, usage table header available" + ": %s", usage_support_type_, + has_provider_session_token() ? "yes" : "no", + usage_table_header_ == nullptr ? "no" : "yes"); return INCORRECT_USAGE_SUPPORT_TYPE_2; } diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index d1b659b2..ec18da19 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -349,7 +349,8 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( } // TODO(rfrias): Refactor to avoid needing to call CdmSession - if (cdm_session) { + if (cdm_session && + cdm_session->get_usage_support_type() == kUsageEntrySupport) { CdmResponseType status = cdm_session->UpdateUsageEntryInformation(); if (NO_ERROR != status) return status; } @@ -628,7 +629,8 @@ bool CdmLicense::RestoreOfflineLicense( const CdmKeyMessage& license_request, const CdmKeyResponse& license_response, const CdmKeyResponse& license_renewal_response, int64_t playback_start_time, - int64_t last_playback_time, int64_t grace_period_end_time) { + int64_t last_playback_time, int64_t grace_period_end_time, + CdmSession* cdm_session) { if (license_request.empty() || license_response.empty()) { LOGE( "CdmLicense::RestoreOfflineLicense: key_request or response empty: " @@ -670,9 +672,16 @@ bool CdmLicense::RestoreOfflineLicense( } if (!provider_session_token_.empty()) { + if (cdm_session && + cdm_session->get_usage_support_type() == kUsageEntrySupport) { + CdmResponseType status = cdm_session->UpdateUsageEntryInformation(); + if (NO_ERROR != status) return false; + } + std::string usage_report; CryptoSession::UsageDurationStatus usage_duration_status = CryptoSession::kUsageDurationsInvalid; + int64_t seconds_since_started, seconds_since_last_played; sts = crypto_session_->GenerateUsageReport( provider_session_token_, &usage_report, &usage_duration_status, diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 97c5af01..016fa74f 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -560,6 +560,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case RELEASE_ALL_USAGE_INFO_ERROR_5: *os << "RELEASE_ALL_USAGE_INFO_ERROR_5"; break; + case RELEASE_ALL_USAGE_INFO_ERROR_6: + *os << "RELEASE_ALL_USAGE_INFO_ERROR_6"; + break; case RELEASE_USAGE_INFO_FAILED: *os << "RELEASE_USAGE_INFO_FAILED"; break; case INCORRECT_USAGE_SUPPORT_TYPE_1: diff --git a/libwvdrmengine/cdm/include/cdm_identifier.h b/libwvdrmengine/cdm/include/cdm_identifier.h index e99b9d71..618c4e5b 100644 --- a/libwvdrmengine/cdm/include/cdm_identifier.h +++ b/libwvdrmengine/cdm/include/cdm_identifier.h @@ -25,11 +25,17 @@ struct CdmIdentifier { // The origin. May be blank if the app does not set an origin, which is // the likely behavior of most non-web-browser apps. std::string origin; + + // The application package name provided by the application. This is used to + // provide a friendly name of the application package for the purposes of + // logging and metrics. + std::string app_package_name; }; // Provide comparison operators inline bool operator==(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { - return lhs.spoid == rhs.spoid && lhs.origin == rhs.origin; + return lhs.spoid == rhs.spoid && lhs.origin == rhs.origin + && lhs.app_package_name == rhs.app_package_name; } inline bool operator!=(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { @@ -37,8 +43,11 @@ inline bool operator!=(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { } inline bool operator<(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { - return (lhs.spoid < rhs.spoid) || - ((lhs.spoid == rhs.spoid) && lhs.origin < rhs.origin); + return (lhs.spoid < rhs.spoid) + || ((lhs.spoid == rhs.spoid) + && (lhs.origin < rhs.origin + || (lhs.origin == rhs.origin + && lhs.app_package_name < rhs.app_package_name))); } inline bool operator>(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { @@ -56,7 +65,8 @@ inline bool operator>=(const CdmIdentifier& lhs, const CdmIdentifier& rhs) { // Provide default static const CdmIdentifier kDefaultCdmIdentifier = { EMPTY_SPOID, - EMPTY_ORIGIN + EMPTY_ORIGIN, + EMPTY_APP_PACKAGE_NAME }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/metrics/include/metrics_collections.h b/libwvdrmengine/cdm/metrics/include/metrics_collections.h index e720408b..15e25133 100644 --- a/libwvdrmengine/cdm/metrics/include/metrics_collections.h +++ b/libwvdrmengine/cdm/metrics/include/metrics_collections.h @@ -263,6 +263,8 @@ class EngineMetrics { void Serialize(drm_metrics::MetricsGroup* metric_group, bool completed_only, bool clear_serialized_sessions); + void SetAppPackageName(const std::string& app_package_name); + // Metrics recorded at the engine level. EventMetric cdm_engine_add_key_; ValueMetric cdm_engine_cdm_version_; @@ -288,6 +290,7 @@ class EngineMetrics { Lock session_metrics_lock_; std::vector session_metrics_list_; CryptoMetrics crypto_metrics_; + std::string app_package_name_; void SerializeEngineMetrics(drm_metrics::MetricsGroup* out); }; diff --git a/libwvdrmengine/cdm/metrics/src/metrics.proto b/libwvdrmengine/cdm/metrics/src/metrics.proto index 4df1fe53..02c5af24 100644 --- a/libwvdrmengine/cdm/metrics/src/metrics.proto +++ b/libwvdrmengine/cdm/metrics/src/metrics.proto @@ -33,4 +33,7 @@ message MetricsGroup { // Allow multiple sub groups of metrics. repeated MetricsGroup metric_sub_group = 2; + + // Name of the application package associated with the metrics. + optional string app_package_name = 3; } diff --git a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp index c70f2da4..2e81d5dd 100644 --- a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp +++ b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp @@ -440,7 +440,8 @@ EngineMetrics::EngineMetrics() : cdm_engine_unprovision_( "/drm/widevine/cdm_engine/unprovision", "error", - "security_level") { + "security_level"), + app_package_name_("") { } EngineMetrics::~EngineMetrics() { @@ -482,14 +483,20 @@ void EngineMetrics::Serialize(drm_metrics::MetricsGroup* metric_group, OemCryptoDynamicAdapterMetrics& adapter_metrics = GetDynamicAdapterMetricsInstance(); adapter_metrics.Serialize(metric_group); - + if (!app_package_name_.empty()) { + metric_group->set_app_package_name(app_package_name_); + } SerializeEngineMetrics(metric_group); std::vector::iterator i; for (i = session_metrics_list_.begin(); i != session_metrics_list_.end(); /* no increment */) { bool serialized = false; if (!completed_only || (*i)->IsCompleted()) { - (*i)->Serialize(metric_group->add_metric_sub_group()); + MetricsGroup* metric_sub_group = metric_group->add_metric_sub_group(); + if (!app_package_name_.empty()) { + metric_sub_group->set_app_package_name(app_package_name_); + } + (*i)->Serialize(metric_sub_group); serialized = true; } @@ -502,6 +509,10 @@ void EngineMetrics::Serialize(drm_metrics::MetricsGroup* metric_group, } } +void EngineMetrics::SetAppPackageName(const std::string& app_package_name) { + app_package_name_ = app_package_name; +} + void EngineMetrics::SerializeEngineMetrics(MetricsGroup* metric_group) { ProtoMetricSerializer serializer(metric_group); cdm_engine_add_key_.Serialize(&serializer); diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index c8d51753..263b84d1 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -380,9 +380,14 @@ CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier( cdms_[identifier].file_system.SetOrigin(identifier.origin); cdms_[identifier].file_system.SetIdentifier( identifier.spoid + identifier.origin); - } - return cdms_[identifier].cdm_engine.get(); + // Set the app package name for use by metrics. + cdms_[identifier].cdm_engine->GetMetrics() + ->SetAppPackageName(identifier.app_package_name); + } + CdmEngine* cdm_engine = cdms_[identifier].cdm_engine.get(); + + return cdm_engine; } CdmEngine* WvContentDecryptionModule::GetCdmForSessionId( diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index e4eccc16..fe95d396 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -51,6 +51,7 @@ const int kHttpInternalServerError = 500; const wvcdm::CdmIdentifier kExampleIdentifier = { wvcdm::EMPTY_SPOID, + "com.example", "com.example" }; @@ -2023,55 +2024,6 @@ TEST_F(WvCdmRequestLicenseTest, VerifyKeyRequestResponse(g_license_server, client_auth); } -TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) { - Unprovision(); - Provision(kLevelDefault); - - // override default settings unless configured through the command line - std::string key_id; - std::string client_auth; - GetOfflineConfiguration(&key_id, &client_auth); - - decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, - &session_id_); - GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth); - - CdmKeySetId key_set_id = key_set_id_; - EXPECT_FALSE(key_set_id_.empty()); - decryptor_.CloseSession(session_id_); - - session_id_.clear(); - key_set_id_.clear(); - StrictMock listener; - decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, &listener, - &session_id_); - CdmSessionId restore_session_id = session_id_; - EXPECT_CALL( - listener, - OnSessionKeysChange( - restore_session_id, - AllOf(Each(Pair(_, kKeyStatusUsable)), Not(IsEmpty())), true)); - EXPECT_CALL(listener, OnExpirationUpdate(restore_session_id, _)); - EXPECT_EQ(wvcdm::KEY_ADDED, - decryptor_.RestoreKey(restore_session_id, key_set_id)); - - session_id_.clear(); - key_set_id_.clear(); - // Maybe called since VerifyKeyRequestResponse could take some time. - EXPECT_CALL(listener, OnSessionRenewalNeeded(restore_session_id)) - .Times(AtLeast(0)); - EXPECT_CALL( - listener, - OnSessionKeysChange( - restore_session_id, - AllOf(Each(Pair(_, kKeyStatusExpired)), Not(IsEmpty())), false)); - GenerateKeyRelease(key_set_id); - key_set_id_ = key_set_id; - VerifyKeyRequestResponse(g_license_server, client_auth); - decryptor_.CloseSession(restore_session_id); -} - // This test verifies that repeated generation of the key release message // for the same key_set_id results in the previous session being // deallocated (rather than leaked) and a new one allocated. diff --git a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp index 169cc280..e9963a90 100644 --- a/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp +++ b/libwvdrmengine/cdm/test/wv_cdm_metrics_test.cpp @@ -106,7 +106,7 @@ TEST_F(WvContentDecryptionModuleMetricsTest, EngineAndSessionMetrics) { TEST_F(WvContentDecryptionModuleMetricsTest, MultipleEngineMetric) { CdmSessionId session_id; wvcdm::CdmKeySystem key_system("com.widevine"); - CdmIdentifier identifier = { "foo", "bar" }; + CdmIdentifier identifier = { "foo", "bar", "baz" }; // Openning the session will fail with NEEDS_PROVISIONING error. But it will // still create some session-level stats. @@ -146,6 +146,9 @@ TEST_F(WvContentDecryptionModuleMetricsTest, MultipleEngineMetric) { metrics.metric_sub_group(i).metric_sub_group(0).metric(0).name(), StrEq("/drm/widevine/cdm_session/session_id")); } + + // Verify that the second metrics app package name is set. + EXPECT_THAT(metrics.metric_sub_group(1).app_package_name(), StrEq("baz")); } } diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index f12c1bdd..d6b79dfc 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -274,10 +274,11 @@ enum { kParseResponseError2 = ERROR_DRM_VENDOR_MIN + 261, kParseResponseError3 = ERROR_DRM_VENDOR_MIN + 262, kParseResponseError4 = ERROR_DRM_VENDOR_MIN + 263, + kReleaseAllUsageInfoError6 = ERROR_DRM_VENDOR_MIN + 264, // 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 + 263, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 264, // 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 ab945b2b..56225b94 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -499,6 +499,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kReleaseAllUsageInfoError4; case wvcdm::RELEASE_ALL_USAGE_INFO_ERROR_5: return kReleaseAllUsageInfoError5; + case wvcdm::RELEASE_ALL_USAGE_INFO_ERROR_6: + return kReleaseAllUsageInfoError6; case wvcdm::RELEASE_USAGE_INFO_FAILED: return android::ERROR_DRM_TAMPER_DETECTED; case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_1: diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index df2f41c0..a752a2a5 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -286,6 +286,7 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) { case wvcdm::USAGE_INVALID_LOAD_ENTRY: case wvcdm::RELEASE_ALL_USAGE_INFO_ERROR_4: case wvcdm::RELEASE_ALL_USAGE_INFO_ERROR_5: + case wvcdm::RELEASE_ALL_USAGE_INFO_ERROR_6: case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_1: case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2: case wvcdm::NO_USAGE_ENTRIES: diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp index 2bbca746..cc9003d6 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -1375,7 +1375,9 @@ WVDrmPlugin::CdmIdentifierBuilder::CdmIdentifierBuilder( mIsIdentifierSealed(false), mUseSpoid(useSpoid), mAppPackageName(appPackageName), - mParent(parent) {} + mParent(parent) { + mCdmIdentifier.app_package_name = mAppPackageName; +} Status WVDrmPlugin::CdmIdentifierBuilder::getCdmIdentifier( CdmIdentifier* identifier) {