| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/blink/webencryptedmediaclient_impl.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/histogram.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "media/base/key_systems.h" |
| #include "media/base/media_client.h" |
| #include "media/base/media_permission.h" |
| #include "media/blink/webcontentdecryptionmodule_impl.h" |
| #include "media/blink/webcontentdecryptionmoduleaccess_impl.h" |
| #include "third_party/WebKit/public/platform/URLConversion.h" |
| #include "third_party/WebKit/public/platform/WebContentDecryptionModuleResult.h" |
| #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h" |
| #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h" |
| #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" |
| #include "third_party/WebKit/public/platform/WebString.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| namespace media { |
| |
| namespace { |
| |
| // Used to name UMAs in Reporter. |
| const char kKeySystemSupportUMAPrefix[] = |
| "Media.EME.RequestMediaKeySystemAccess."; |
| |
| } // namespace |
| |
| // Report usage of key system to UMA. There are 2 different counts logged: |
| // 1. The key system is requested. |
| // 2. The requested key system and options are supported. |
| // Each stat is only reported once per renderer frame per key system. |
| // Note that WebEncryptedMediaClientImpl is only created once by each |
| // renderer frame. |
| class WebEncryptedMediaClientImpl::Reporter { |
| public: |
| enum KeySystemSupportStatus { |
| KEY_SYSTEM_REQUESTED = 0, |
| KEY_SYSTEM_SUPPORTED = 1, |
| KEY_SYSTEM_SUPPORT_STATUS_COUNT |
| }; |
| |
| explicit Reporter(const std::string& key_system_for_uma) |
| : uma_name_(kKeySystemSupportUMAPrefix + key_system_for_uma), |
| is_request_reported_(false), |
| is_support_reported_(false) {} |
| ~Reporter() {} |
| |
| void ReportRequested() { |
| if (is_request_reported_) |
| return; |
| Report(KEY_SYSTEM_REQUESTED); |
| is_request_reported_ = true; |
| } |
| |
| void ReportSupported() { |
| DCHECK(is_request_reported_); |
| if (is_support_reported_) |
| return; |
| Report(KEY_SYSTEM_SUPPORTED); |
| is_support_reported_ = true; |
| } |
| |
| private: |
| void Report(KeySystemSupportStatus status) { |
| // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros |
| // require the names to be constant throughout the process' lifetime. |
| base::LinearHistogram::FactoryGet( |
| uma_name_, 1, KEY_SYSTEM_SUPPORT_STATUS_COUNT, |
| KEY_SYSTEM_SUPPORT_STATUS_COUNT + 1, |
| base::Histogram::kUmaTargetedHistogramFlag)->Add(status); |
| } |
| |
| const std::string uma_name_; |
| bool is_request_reported_; |
| bool is_support_reported_; |
| }; |
| |
| WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl( |
| base::Callback<bool(void)> are_secure_codecs_supported_cb, |
| CdmFactory* cdm_factory, |
| MediaPermission* media_permission) |
| : are_secure_codecs_supported_cb_(are_secure_codecs_supported_cb), |
| cdm_factory_(cdm_factory), |
| key_system_config_selector_(KeySystems::GetInstance(), media_permission), |
| weak_factory_(this) { |
| DCHECK(cdm_factory_); |
| } |
| |
| WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() { |
| } |
| |
| void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess( |
| blink::WebEncryptedMediaRequest request) { |
| GetReporter(request.keySystem())->ReportRequested(); |
| |
| if (GetMediaClient()) { |
| GURL security_origin(url::Origin(request.getSecurityOrigin()).GetURL()); |
| |
| GetMediaClient()->RecordRapporURL("Media.OriginUrl.EME", security_origin); |
| |
| if (!request.getSecurityOrigin().isPotentiallyTrustworthy()) { |
| GetMediaClient()->RecordRapporURL("Media.OriginUrl.EME.Insecure", |
| security_origin); |
| } |
| } |
| |
| key_system_config_selector_.SelectConfig( |
| request.keySystem(), request.supportedConfigurations(), |
| request.getSecurityOrigin(), are_secure_codecs_supported_cb_.Run(), |
| base::Bind(&WebEncryptedMediaClientImpl::OnRequestSucceeded, |
| weak_factory_.GetWeakPtr(), request), |
| base::Bind(&WebEncryptedMediaClientImpl::OnRequestNotSupported, |
| weak_factory_.GetWeakPtr(), request)); |
| } |
| |
| void WebEncryptedMediaClientImpl::CreateCdm( |
| const blink::WebString& key_system, |
| const blink::WebSecurityOrigin& security_origin, |
| const CdmConfig& cdm_config, |
| std::unique_ptr<blink::WebContentDecryptionModuleResult> result) { |
| WebContentDecryptionModuleImpl::Create( |
| cdm_factory_, key_system, security_origin, cdm_config, std::move(result)); |
| } |
| |
| void WebEncryptedMediaClientImpl::OnRequestSucceeded( |
| blink::WebEncryptedMediaRequest request, |
| const blink::WebMediaKeySystemConfiguration& accumulated_configuration, |
| const CdmConfig& cdm_config) { |
| GetReporter(request.keySystem())->ReportSupported(); |
| // TODO(sandersd): Pass |are_secure_codecs_required| along and use it to |
| // configure the CDM security level and use of secure surfaces on Android. |
| |
| // If the frame is closed while the permission prompt is displayed, |
| // the permission prompt is dismissed and this may result in the |
| // requestMediaKeySystemAccess request succeeding. However, the blink |
| // objects may have been cleared, so check if this is the case and simply |
| // reject the request. |
| blink::WebSecurityOrigin origin = request.getSecurityOrigin(); |
| if (origin.isNull()) { |
| request.requestNotSupported("Unable to create MediaKeySystemAccess"); |
| return; |
| } |
| |
| request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create( |
| request.keySystem(), origin, accumulated_configuration, cdm_config, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void WebEncryptedMediaClientImpl::OnRequestNotSupported( |
| blink::WebEncryptedMediaRequest request, |
| const blink::WebString& error_message) { |
| request.requestNotSupported(error_message); |
| } |
| |
| WebEncryptedMediaClientImpl::Reporter* WebEncryptedMediaClientImpl::GetReporter( |
| const blink::WebString& key_system) { |
| // Assumes that empty will not be found by GetKeySystemNameForUMA(). |
| // TODO(sandersd): Avoid doing ASCII conversion more than once. |
| std::string key_system_ascii; |
| if (key_system.containsOnlyASCII()) |
| key_system_ascii = key_system.ascii(); |
| |
| // Return a per-frame singleton so that UMA reports will be once-per-frame. |
| std::string uma_name = GetKeySystemNameForUMA(key_system_ascii); |
| Reporter* reporter = reporters_.get(uma_name); |
| if (!reporter) { |
| reporter = new Reporter(uma_name); |
| reporters_.add(uma_name, base::WrapUnique(reporter)); |
| } |
| return reporter; |
| } |
| |
| } // namespace media |