Commit 22f8a43c authored by xhwang's avatar xhwang Committed by Commit bot

media: Add OutputProtectionProxy

This class handles output protection query and request in the browser
process on all platforms. On ChromeOS, it delegates the operations on
the hardware displays to OutputProtectionDelegate. On other platforms,
it does not check hardware displays. On all platforms, it checks
whether there is any network link and adds it to the existing link mask.

This class will also be used to implement mojo OutputProtection service
on all platforms.

This CL also updated PPAPI cdm adapter and PPAPI code to enable output
protection calls on all platforms. A unit test is added via external
clear key tests.

BUG=592122,589618
TEST=Added new tests.

Review-Url: https://codereview.chromium.org/2085063002
Cr-Commit-Position: refs/heads/master@{#401896}
parent c467abfd
......@@ -7,7 +7,6 @@
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "build/build_config.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
......@@ -133,18 +132,7 @@ void OutputProtectionDelegate::QueryStatusComplete(
return;
}
uint32_t link_mask = response.link_mask;
// If we successfully retrieved the device level status, check for capturers.
if (response.success) {
const bool insecure_capture_detected =
MediaCaptureDevicesDispatcher::GetInstance()
->IsInsecureCapturingInProgress(render_process_id_,
render_frame_id_);
if (insecure_capture_detected)
link_mask |= ui::DISPLAY_CONNECTION_TYPE_NETWORK;
}
callback.Run(response.success, link_mask, response.protection_mask);
callback.Run(response.success, response.link_mask, response.protection_mask);
}
void OutputProtectionDelegate::EnableProtectionComplete(
......
......@@ -34,10 +34,18 @@
// Available key systems.
const char kClearKeyKeySystem[] = "org.w3.clearkey";
const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
// Variants of External Clear Key key system to test different scenarios.
// To add a new variant, make sure you also update:
// - media/test/data/eme_player_js/globals.js
// - AddExternalClearKey() in chrome_key_systems.cc
// - CreateCdmInstance() in clear_key_cdm.cc
const char kExternalClearKeyFileIOTestKeySystem[] =
"org.chromium.externalclearkey.fileiotest";
const char kExternalClearKeyInitializeFailKeySystem[] =
"org.chromium.externalclearkey.initializefail";
const char kExternalClearKeyOutputProtectionTestKeySystem[] =
"org.chromium.externalclearkey.outputprotectiontest";
const char kExternalClearKeyCrashKeySystem[] =
"org.chromium.externalclearkey.crash";
......@@ -57,7 +65,7 @@ const char kLoadableSession[] = "LoadableSession";
const char kUnknownSession[] = "UnknownSession";
// EME-specific test results and errors.
const char kFileIOTestSuccess[] = "FILE_IO_TEST_SUCCESS";
const char kUnitTestSuccess[] = "UNIT_TEST_SUCCESS";
const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
const char kEmeGenerateRequestFailed[] = "EME_GENERATEREQUEST_FAILED";
const char kEmeSessionNotFound[] = "EME_SESSION_NOT_FOUND";
......@@ -625,8 +633,14 @@ IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, CDMExpectedCrash) {
}
IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, FileIOTest) {
TestNonPlaybackCases(kExternalClearKeyFileIOTestKeySystem,
kFileIOTestSuccess);
TestNonPlaybackCases(kExternalClearKeyFileIOTestKeySystem, kUnitTestSuccess);
}
// TODO(xhwang): Investigate how to fake capturing activities to test the
// network link detection logic in OutputProtectionProxy.
IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, OutputProtectionTest) {
TestNonPlaybackCases(kExternalClearKeyOutputProtectionTestKeySystem,
kUnitTestSuccess);
}
IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, LoadLoadableSession) {
......
// Copyright 2016 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 "chrome/browser/media/output_protection_proxy.h"
#include "build/build_config.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/display/types/display_constants.h"
namespace chrome {
OutputProtectionProxy::OutputProtectionProxy(int render_process_id,
int render_frame_id)
: render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
#if defined(OS_CHROMEOS)
output_protection_delegate_(render_process_id, render_frame_id),
#endif // defined(OS_CHROMEOS)
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
}
OutputProtectionProxy::~OutputProtectionProxy() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
void OutputProtectionProxy::QueryStatus(const QueryStatusCallback& callback) {
DVLOG(1) << __FUNCTION__;
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
#if defined(OS_CHROMEOS)
output_protection_delegate_.QueryStatus(
base::Bind(&OutputProtectionProxy::ProcessQueryStatusResult,
weak_ptr_factory_.GetWeakPtr(), callback));
#else // defined(OS_CHROMEOS)
ProcessQueryStatusResult(callback, true, 0, 0);
#endif // defined(OS_CHROMEOS)
}
void OutputProtectionProxy::EnableProtection(
uint32_t desired_method_mask,
const EnableProtectionCallback& callback) {
DVLOG(1) << __FUNCTION__;
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
#if defined(OS_CHROMEOS)
output_protection_delegate_.EnableProtection(desired_method_mask, callback);
#else // defined(OS_CHROMEOS)
NOTIMPLEMENTED();
callback.Run(false);
#endif // defined(OS_CHROMEOS)
}
void OutputProtectionProxy::ProcessQueryStatusResult(
const QueryStatusCallback& callback,
bool success,
uint32_t link_mask,
uint32_t protection_mask) {
DVLOG(1) << __FUNCTION__ << ": " << success << ", " << link_mask;
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
// TODO(xjz): Investigate whether this check (and the checks in
// OutputProtectionDelegate) should be removed.
if (!rfh) {
LOG(WARNING) << "RenderFrameHost is not alive.";
callback.Run(false, 0, 0);
return;
}
uint32_t new_link_mask = link_mask;
// If we successfully retrieved the device level status, check for capturers.
if (success) {
const bool is_insecure_capture_detected =
MediaCaptureDevicesDispatcher::GetInstance()
->IsInsecureCapturingInProgress(render_process_id_,
render_frame_id_);
if (is_insecure_capture_detected)
new_link_mask |= ui::DISPLAY_CONNECTION_TYPE_NETWORK;
}
callback.Run(success, new_link_mask, protection_mask);
}
} // namespace chrome
// Copyright 2016 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.
#ifndef CHROME_BROWSER_MEDIA_OUTPUT_PROTECTION_PROXY_H_
#define CHROME_BROWSER_MEDIA_OUTPUT_PROTECTION_PROXY_H_
#include <stdint.h>
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/display/output_protection_delegate.h"
#endif
namespace chrome {
// A class to query output protection status and/or enable output protection.
//
// On Chrome OS, operations on the physical displays are delegated to
// OutputProtectionDelegate. On other platforms, physical displays are not
// checked.
//
// On all platforms, in ProcessQueryStatusResult(), this class checks the
// network link and adds it to the existing link mask.
//
// All methods except constructor should be invoked in UI thread.
class OutputProtectionProxy {
public:
typedef base::Callback<void(bool /* success */,
uint32_t /* link_mask */,
uint32_t /* protection_mask*/)>
QueryStatusCallback;
typedef base::Callback<void(bool /* success */)> EnableProtectionCallback;
OutputProtectionProxy(int render_process_id, int render_frame_id);
void QueryStatus(const QueryStatusCallback& callback);
void EnableProtection(uint32_t desired_method_mask,
const EnableProtectionCallback& callback);
private:
// Makes sure this class can only be deleted on the UI thread.
friend class base::DeleteHelper<OutputProtectionProxy>;
friend struct content::BrowserThread::DeleteOnThread<
content::BrowserThread::UI>;
~OutputProtectionProxy();
// Callbacks for QueryStatus(). It also checks the network link and adds it
// to the |link_mask|.
void ProcessQueryStatusResult(const QueryStatusCallback& callback,
bool success,
uint32_t link_mask,
uint32_t protection_mask);
// Used to lookup the WebContents associated with the render frame.
int render_process_id_;
int render_frame_id_;
#if defined(OS_CHROMEOS)
chromeos::OutputProtectionDelegate output_protection_delegate_;
#endif
base::WeakPtrFactory<OutputProtectionProxy> weak_ptr_factory_;
};
} // namespace chrome
#endif // CHROME_BROWSER_MEDIA_OUTPUT_PROTECTION_PROXY_H_
......@@ -60,7 +60,6 @@ ChromeBrowserPepperHostFactory::CreateResourceHost(
host_->GetPpapiHost(), instance, resource, pv_filter));
}
#endif
#if defined(OS_CHROMEOS)
case PpapiHostMsg_OutputProtection_Create::ID: {
scoped_refptr<ResourceMessageFilter> output_protection_filter(
new chrome::PepperOutputProtectionMessageFilter(host_, instance));
......@@ -68,7 +67,6 @@ ChromeBrowserPepperHostFactory::CreateResourceHost(
new MessageFilterHost(host_->GetPpapiHost(), instance, resource,
output_protection_filter));
}
#endif
}
}
......
......@@ -5,6 +5,7 @@
#include "chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h"
#include "build/build_config.h"
#include "chrome/browser/media/output_protection_proxy.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
......@@ -14,19 +15,14 @@
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/display/output_protection_delegate.h"
#include "ui/display/types/display_constants.h"
#endif
namespace chrome {
namespace {
#if defined(OS_CHROMEOS)
static_assert(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE) ==
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_NONE),
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_NONE),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE value mismatch");
static_assert(
static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN) ==
......@@ -37,14 +33,14 @@ static_assert(
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_INTERNAL),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL value mismatch");
static_assert(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA) ==
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_VGA),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA value mismatch");
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_VGA),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA value mismatch");
static_assert(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI) ==
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_HDMI),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI value mismatch");
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_HDMI),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI value mismatch");
static_assert(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI) ==
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_DVI),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI value mismatch");
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_DVI),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI value mismatch");
static_assert(
static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT) ==
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_DISPLAYPORT),
......@@ -54,12 +50,11 @@ static_assert(
static_cast<int>(ui::DISPLAY_CONNECTION_TYPE_NETWORK),
"PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK value mismatch");
static_assert(static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE) ==
static_cast<int>(ui::CONTENT_PROTECTION_METHOD_NONE),
"PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE value mismatch");
static_cast<int>(ui::CONTENT_PROTECTION_METHOD_NONE),
"PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE value mismatch");
static_assert(static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP) ==
static_cast<int>(ui::CONTENT_PROTECTION_METHOD_HDCP),
"PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP value mismatch");
#endif
static_cast<int>(ui::CONTENT_PROTECTION_METHOD_HDCP),
"PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP value mismatch");
} // namespace
......@@ -67,26 +62,15 @@ PepperOutputProtectionMessageFilter::PepperOutputProtectionMessageFilter(
content::BrowserPpapiHost* host,
PP_Instance instance)
: weak_ptr_factory_(this) {
#if defined(OS_CHROMEOS)
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
int render_process_id = 0;
int render_frame_id = 0;
host->GetRenderFrameIDsForInstance(
instance, &render_process_id, &render_frame_id);
delegate_ = new chromeos::OutputProtectionDelegate(render_process_id,
render_frame_id);
#else
NOTIMPLEMENTED();
#endif
proxy_.reset(new OutputProtectionProxy(render_process_id, render_frame_id));
}
PepperOutputProtectionMessageFilter::~PepperOutputProtectionMessageFilter() {
#if defined(OS_CHROMEOS)
content::BrowserThread::DeleteSoon(
content::BrowserThread::UI, FROM_HERE, delegate_);
delegate_ = NULL;
#endif
}
PepperOutputProtectionMessageFilter::~PepperOutputProtectionMessageFilter() {}
scoped_refptr<base::TaskRunner>
PepperOutputProtectionMessageFilter::OverrideTaskRunnerForMessage(
......@@ -109,35 +93,25 @@ int32_t PepperOutputProtectionMessageFilter::OnResourceMessageReceived(
int32_t PepperOutputProtectionMessageFilter::OnQueryStatus(
ppapi::host::HostMessageContext* context) {
#if defined(OS_CHROMEOS)
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
delegate_->QueryStatus(
proxy_->QueryStatus(
base::Bind(&PepperOutputProtectionMessageFilter::OnQueryStatusComplete,
weak_ptr_factory_.GetWeakPtr(), reply_context));
return PP_OK_COMPLETIONPENDING;
#else
NOTIMPLEMENTED();
return PP_ERROR_NOTSUPPORTED;
#endif
}
int32_t PepperOutputProtectionMessageFilter::OnEnableProtection(
ppapi::host::HostMessageContext* context,
uint32_t desired_method_mask) {
#if defined(OS_CHROMEOS)
ppapi::host::ReplyMessageContext reply_context =
context->MakeReplyMessageContext();
delegate_->EnableProtection(
proxy_->EnableProtection(
desired_method_mask,
base::Bind(
&PepperOutputProtectionMessageFilter::OnEnableProtectionComplete,
weak_ptr_factory_.GetWeakPtr(), reply_context));
return PP_OK_COMPLETIONPENDING;
#else
NOTIMPLEMENTED();
return PP_ERROR_NOTSUPPORTED;
#endif
}
void PepperOutputProtectionMessageFilter::OnQueryStatusComplete(
......
......@@ -7,8 +7,11 @@
#include <stdint.h>
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "build/build_config.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/host/resource_message_filter.h"
......@@ -23,14 +26,10 @@ struct HostMessageContext;
} // namespace host
} // namespace ppapi
#if defined(OS_CHROMEOS)
namespace chromeos {
class OutputProtectionDelegate;
}
#endif
namespace chrome {
class OutputProtectionProxy;
class PepperOutputProtectionMessageFilter
: public ppapi::host::ResourceMessageFilter {
public:
......@@ -60,10 +59,9 @@ class PepperOutputProtectionMessageFilter
ppapi::host::ReplyMessageContext reply_context,
bool success);
#if defined(OS_CHROMEOS)
// Delegate. Should be deleted in UI thread.
chromeos::OutputProtectionDelegate* delegate_;
#endif
std::unique_ptr<OutputProtectionProxy,
content::BrowserThread::DeleteOnUIThread>
proxy_;
base::WeakPtrFactory<PepperOutputProtectionMessageFilter> weak_ptr_factory_;
......
......@@ -388,6 +388,8 @@
'browser/media/midi_permission_context.h',
'browser/media/native_desktop_media_list.cc',
'browser/media/native_desktop_media_list.h',
'browser/media/output_protection_proxy.cc',
'browser/media/output_protection_proxy.h',
'browser/media/permission_bubble_media_access_handler.cc',
'browser/media/permission_bubble_media_access_handler.h',
'browser/media/router/media_router_feature.cc',
......
......@@ -134,6 +134,8 @@ static void AddExternalClearKey(
"org.chromium.externalclearkey.decryptonly";
static const char kExternalClearKeyFileIOTestKeySystem[] =
"org.chromium.externalclearkey.fileiotest";
static const char kExternalClearKeyOutputProtectionTestKeySystem[] =
"org.chromium.externalclearkey.outputprotectiontest";
static const char kExternalClearKeyInitializeFailKeySystem[] =
"org.chromium.externalclearkey.initializefail";
static const char kExternalClearKeyCrashKeySystem[] =
......@@ -154,10 +156,14 @@ static void AddExternalClearKey(
concrete_key_systems->emplace_back(
new ExternalClearKeyProperties(kExternalClearKeyDecryptOnlyKeySystem));
// A key system that triggers FileIO test in ClearKeyCdm.
// A key system that triggers the FileIO test in ClearKeyCdm.
concrete_key_systems->emplace_back(
new ExternalClearKeyProperties(kExternalClearKeyFileIOTestKeySystem));
// A key system that triggers the output protection test in ClearKeyCdm.
concrete_key_systems->emplace_back(new ExternalClearKeyProperties(
kExternalClearKeyOutputProtectionTestKeySystem));
// A key system that Chrome thinks is supported by ClearKeyCdm, but actually
// will be refused by ClearKeyCdm. This is to test the CDM initialization
// failure case.
......
......@@ -58,10 +58,14 @@ static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries();
const char kClearKeyCdmVersion[] = "0.1.0.1";
const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
// Variants of External Clear Key key system to test different scenarios.
const char kExternalClearKeyDecryptOnlyKeySystem[] =
"org.chromium.externalclearkey.decryptonly";
const char kExternalClearKeyFileIOTestKeySystem[] =
"org.chromium.externalclearkey.fileiotest";
const char kExternalClearKeyOutputProtectionTestKeySystem[] =
"org.chromium.externalclearkey.outputprotectiontest";
const char kExternalClearKeyCrashKeySystem[] =
"org.chromium.externalclearkey.crash";
......@@ -82,8 +86,10 @@ const int64_t kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond;
// |kRenewalHeader|, it's a renewal message. Otherwise, it's a key request.
// FIXME(jrummell): Remove this once prefixed EME goes away.
const char kRenewalHeader[] = "RENEWAL";
// CDM file IO test result header.
const char kFileIOTestResultHeader[] = "FILEIOTESTRESULT";
// CDM unit test result header. Must be in sync with UNIT_TEST_RESULT_HEADER in
// media/test/data/eme_player_js/globals.js.
const char kUnitTestResultHeader[] = "UNIT_TEST_RESULT";
// Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is
// empty, an empty (end-of-stream) media::DecoderBuffer is returned.
......@@ -119,8 +125,8 @@ static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom(
return output_buffer;
}
static std::string GetFileIOTestResultMessage(bool success) {
std::string message(kFileIOTestResultHeader);
static std::string GetUnitTestResultMessage(bool success) {
std::string message(kUnitTestResultHeader);
message += success ? '1' : '0';
return message;
}
......@@ -232,6 +238,7 @@ void* CreateCdmInstance(int cdm_interface_version,
if (key_system_string != kExternalClearKeyKeySystem &&
key_system_string != kExternalClearKeyDecryptOnlyKeySystem &&
key_system_string != kExternalClearKeyFileIOTestKeySystem &&
key_system_string != kExternalClearKeyOutputProtectionTestKeySystem &&
key_system_string != kExternalClearKeyCrashKeySystem) {
DVLOG(1) << "Unsupported key system:" << key_system_string;
return NULL;
......@@ -269,7 +276,8 @@ ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host,
key_system_(key_system),
has_received_keys_change_event_for_emulated_loadsession_(false),
timer_delay_ms_(kInitialTimerDelayMs),
renewal_timer_set_(false) {
renewal_timer_set_(false),
is_running_output_protection_test_(false) {
#if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
channel_count_ = 0;
bits_per_channel_ = 0;
......@@ -306,8 +314,11 @@ void ClearKeyCdm::CreateSessionAndGenerateRequest(
std::vector<uint8_t>(init_data, init_data + init_data_size),
std::move(promise));
if (key_system_ == kExternalClearKeyFileIOTestKeySystem)
if (key_system_ == kExternalClearKeyFileIOTestKeySystem) {
StartFileIOTest();
} else if (key_system_ == kExternalClearKeyOutputProtectionTestKeySystem) {
StartOutputProtectionTest();
}
}
// Loads a emulated stored session. Currently only |kLoadableSessionId|
......@@ -694,7 +705,25 @@ void ClearKeyCdm::OnQueryOutputProtectionStatus(
cdm::QueryResult result,
uint32_t link_mask,
uint32_t output_protection_mask) {
NOTIMPLEMENTED();
if (!is_running_output_protection_test_) {
NOTREACHED() << "OnQueryOutputProtectionStatus() called unexpectedly.";
return;
}
is_running_output_protection_test_ = false;
// On Chrome OS, status query will fail on Linux Chrome OS build. So we ignore
// the query result. On all other platforms, status query should succeed.
// TODO(xhwang): Improve the check on Chrome OS builds. For example, use
// base::SysInfo::IsRunningOnChromeOS() to differentiate between real Chrome OS
// build and Linux Chrome OS build.
#if !defined(OS_CHROMEOS)
if (result != cdm::kQuerySucceeded || link_mask != 0) {
OnUnitTestComplete(false);
return;
}
#endif
OnUnitTestComplete(true);
};
void ClearKeyCdm::LoadLoadableSession() {
......@@ -903,6 +932,13 @@ cdm::Status ClearKeyCdm::GenerateFakeAudioFrames(
}
#endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
void ClearKeyCdm::OnUnitTestComplete(bool success) {
std::string message = GetUnitTestResultMessage(success);
host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(),
cdm::kLicenseRequest, message.data(),
message.length(), NULL, 0);
}
void ClearKeyCdm::StartFileIOTest() {
file_io_test_runner_.reset(new FileIOTestRunner(
base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_))));
......@@ -912,11 +948,13 @@ void ClearKeyCdm::StartFileIOTest() {
void ClearKeyCdm::OnFileIOTestComplete(bool success) {
DVLOG(1) << __FUNCTION__ << ": " << success;
std::string message = GetFileIOTestResultMessage(success);
host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(),
cdm::kLicenseRequest, message.data(),
message.length(), NULL, 0);
OnUnitTestComplete(success);
file_io_test_runner_.reset();
}
void ClearKeyCdm::StartOutputProtectionTest() {
is_running_output_protection_test_ = true;
host_->QueryOutputProtectionStatus();
}
} // namespace media
......@@ -140,11 +140,15 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
cdm::AudioFrames* audio_frames);
#endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
void OnUnitTestComplete(bool success);
void StartFileIOTest();
// Callback for CDM File IO test.
void OnFileIOTestComplete(bool success);
void StartOutputProtectionTest();
// Keep track of the last session created.
void SetSessionId(const std::string& session_id);
......@@ -209,6 +213,8 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
std::unique_ptr<FileIOTestRunner> file_io_test_runner_;
bool is_running_output_protection_test_;
DISALLOW_COPY_AND_ASSIGN(ClearKeyCdm);
};
......
......@@ -320,14 +320,14 @@ namespace media {
PpapiCdmAdapter::PpapiCdmAdapter(PP_Instance instance, pp::Module* module)
: pp::Instance(instance),
pp::ContentDecryptor_Private(this),
#if defined(OS_CHROMEOS)
output_protection_(this),
platform_verification_(this),
output_link_mask_(0),
output_protection_mask_(0),
query_output_protection_in_progress_(false),
uma_for_output_protection_query_reported_(false),
uma_for_output_protection_positive_result_reported_(false),
#if defined(OS_CHROMEOS)
platform_verification_(this),
#endif
allocator_(this),
cdm_(NULL),
......@@ -1069,7 +1069,6 @@ void PpapiCdmAdapter::SendPlatformChallenge(const char* service_id,
}
void PpapiCdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
#if defined(OS_CHROMEOS)
int32_t result = output_protection_.EnableProtection(
desired_protection_mask,
callback_factory_.NewCallback(&PpapiCdmAdapter::EnableProtectionDone));
......@@ -1079,11 +1078,9 @@ void PpapiCdmAdapter::EnableOutputProtection(uint32_t desired_protection_mask) {
if (result != PP_OK && result != PP_OK_COMPLETIONPENDING)
CDM_DLOG() << __FUNCTION__ << " failed!";
#endif
}
void PpapiCdmAdapter::QueryOutputProtectionStatus() {
#if defined(OS_CHROMEOS)
PP_DCHECK(!query_output_protection_in_progress_);
output_link_mask_ = output_protection_mask_ = 0;
......@@ -1100,8 +1097,6 @@ void PpapiCdmAdapter::QueryOutputProtectionStatus() {
// Fall through on error and issue an empty OnQueryOutputProtectionStatus().
PP_DCHECK(result != PP_OK);
CDM_DLOG() << __FUNCTION__ << " failed, result = " << result;
#endif
cdm_->OnQueryOutputProtectionStatus(cdm::kQueryFailed, 0, 0);
}
void PpapiCdmAdapter::OnDeferredInitializationDone(cdm::StreamType stream_type,
......@@ -1139,7 +1134,6 @@ cdm::FileIO* PpapiCdmAdapter::CreateFileIO(cdm::FileIOClient* client) {
callback_factory_.NewCallback(&PpapiCdmAdapter::OnFirstFileRead));
}
#if defined(OS_CHROMEOS)
void PpapiCdmAdapter::ReportOutputProtectionUMA(OutputProtectionStatus status) {
pp::UMAPrivate uma_interface(this);
uma_interface.HistogramEnumeration("Media.EME.OutputProtection", status,
......@@ -1169,9 +1163,10 @@ void PpapiCdmAdapter::ReportOutputProtectionQueryResult() {
const uint32_t kProtectableLinks =
cdm::kLinkTypeHDMI | cdm::kLinkTypeDVI | cdm::kLinkTypeDisplayPort;
bool is_unprotectable_link_connected = external_links & ~kProtectableLinks;
bool is_unprotectable_link_connected =
(external_links & ~kProtectableLinks) != 0;
bool is_hdcp_enabled_on_all_protectable_links =
output_protection_mask_ & cdm::kProtectionHDCP;
(output_protection_mask_ & cdm::kProtectionHDCP) != 0;
if (!is_unprotectable_link_connected &&
is_hdcp_enabled_on_all_protectable_links) {
......@@ -1185,6 +1180,7 @@ void PpapiCdmAdapter::ReportOutputProtectionQueryResult() {
// queries and success results.
}
#if defined(OS_CHROMEOS)
void PpapiCdmAdapter::SendPlatformChallengeDone(
int32_t result,
const linked_ptr<PepperPlatformChallengeResponse>& response) {
......@@ -1212,6 +1208,7 @@ void PpapiCdmAdapter::SendPlatformChallengeDone(
signed_data_var.Unmap();
signed_data_signature_var.Unmap();
}
#endif
void PpapiCdmAdapter::EnableProtectionDone(int32_t result) {
// Does nothing since clients must call QueryOutputProtectionStatus() to
......@@ -1237,7 +1234,6 @@ void PpapiCdmAdapter::QueryOutputProtectionStatusDone(int32_t result) {
cdm_->OnQueryOutputProtectionStatus(query_result, output_link_mask_,
output_protection_mask_);
}
#endif
PpapiCdmAdapter::SessionError::SessionError(
cdm::Error error,
......
......@@ -20,12 +20,12 @@
#include "ppapi/c/private/pp_content_decryptor.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/private/content_decryptor_private.h"
#include "ppapi/cpp/private/output_protection_private.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array_buffer.h"
#include "ppapi/utility/completion_callback_factory.h"
#if defined(OS_CHROMEOS)
#include "ppapi/cpp/private/output_protection_private.h"
#include "ppapi/cpp/private/platform_verification.h"
#endif
......@@ -238,11 +238,14 @@ class PpapiCdmAdapter : public pp::Instance,
void LogToConsole(const pp::Var& value);
#endif // !defined(NDEBUG)
#if defined(OS_CHROMEOS)
void ReportOutputProtectionUMA(OutputProtectionStatus status);
void ReportOutputProtectionQuery();
void ReportOutputProtectionQueryResult();
void EnableProtectionDone(int32_t result);
void QueryOutputProtectionStatusDone(int32_t result);
#if defined(OS_CHROMEOS)
struct PepperPlatformChallengeResponse {
pp::Var signed_data;
pp::Var signed_data_signature;
......@@ -252,11 +255,9 @@ class PpapiCdmAdapter : public pp::Instance,
void SendPlatformChallengeDone(
int32_t result,
const linked_ptr<PepperPlatformChallengeResponse>& response);
void EnableProtectionDone(int32_t result);
void QueryOutputProtectionStatusDone(int32_t result);
#endif
pp::OutputProtection_Private output_protection_;
pp::PlatformVerification platform_verification_;
// Same as above, these are only read by QueryOutputProtectionStatusDone().
uint32_t output_link_mask_;
......@@ -267,6 +268,9 @@ class PpapiCdmAdapter : public pp::Instance,
// unprotected external link) have been reported to UMA.
bool uma_for_output_protection_query_reported_;
bool uma_for_output_protection_positive_result_reported_;
#if defined(OS_CHROMEOS)
pp::PlatformVerification platform_verification_;
#endif
PpbBufferAllocator allocator_;
......
......@@ -18,5 +18,5 @@ addScriptTag('media_source_utils.js');
addScriptTag('player_utils.js');
addScriptTag('clearkey_player.js');
addScriptTag('widevine_player.js');
addScriptTag('file_io_test_player.js');
addScriptTag('unit_test_player.js');
addScriptTag('eme_app.js');
......@@ -20,7 +20,7 @@ var DEFAULT_MEDIA_FILE = 'http://shadi.kir/alcatraz/Chrome_44-enc_av.webm';
var KEY_ID = '0123456789012345';
// Unique strings to identify test result expectations.
var FILE_IO_TEST_SUCCESS = 'FILE_IO_TEST_SUCCESS';
var UNIT_TEST_SUCCESS = 'UNIT_TEST_SUCCESS';
var NOTSUPPORTEDERROR = 'NOTSUPPORTEDERROR';
var EME_GENERATEREQUEST_FAILED = 'EME_GENERATEREQUEST_FAILED';
var EME_SESSION_NOT_FOUND = 'EME_SESSION_NOT_FOUND';
......@@ -30,14 +30,16 @@ var EME_ERROR_EVENT = 'EME_ERROR_EVENT';
var EME_MESSAGE_UNEXPECTED_TYPE = 'EME_MESSAGE_UNEXPECTED_TYPE';
var EME_RENEWAL_MISSING_HEADER = 'EME_RENEWAL_MISSING_HEADER';
// Headers used when testing file I/O.
var FILE_IO_TEST_RESULT_HEADER = 'FILEIOTESTRESULT';
// Headers used when running some specific unittests in the external CDM.
var UNIT_TEST_RESULT_HEADER = 'UNIT_TEST_RESULT';
// Available EME key systems to use.
var CLEARKEY = 'org.w3.clearkey';
var EXTERNAL_CLEARKEY = 'org.chromium.externalclearkey';
var WIDEVINE_KEYSYSTEM = 'com.widevine.alpha';
var FILE_IO_TEST_KEYSYSTEM = 'org.chromium.externalclearkey.fileiotest';
var OUTPUT_PROTECTION_TEST_KEYSYSTEM =
'org.chromium.externalclearkey.outputprotectiontest';
// Key system name:value map to show on the document page.
var KEY_SYSTEMS = {
......
......@@ -148,7 +148,8 @@ PlayerUtils.createPlayer = function(video, testConfig) {
case CLEARKEY:
return ClearKeyPlayer;
case FILE_IO_TEST_KEYSYSTEM:
return FileIOTestPlayer;
case OUTPUT_PROTECTION_TEST_KEYSYSTEM:
return UnitTestPlayer;
default:
Utils.timeLog(keySystem + ' is not a known key system');
return ClearKeyPlayer;
......
......@@ -2,18 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// File IO test player is used to test File IO CDM functionality.
function FileIOTestPlayer(video, testConfig) {
// CDM unit test player is used to run a specific test within the CDM. The test
// result is reported via a special key message with UNIT_TEST_RESULT_HEADER
// followed by 1 for success, and 0 for failure.
function UnitTestPlayer(video, testConfig) {
this.video = video;
this.testConfig = testConfig;
}
FileIOTestPlayer.prototype.init = function() {
UnitTestPlayer.prototype.init = function() {
// Returns a promise.
return PlayerUtils.initEMEPlayer(this);
};
FileIOTestPlayer.prototype.registerEventListeners = function() {
UnitTestPlayer.prototype.registerEventListeners = function() {
// Returns a promise.
return PlayerUtils.registerEMEEventListeners(this);
};
......@@ -21,19 +23,19 @@ FileIOTestPlayer.prototype.registerEventListeners = function() {
handleMessage = function(message) {
// The test result is either '0' or '1' appended to the header.
var msg = Utils.convertToUint8Array(message.message);
if (Utils.hasPrefix(msg, FILE_IO_TEST_RESULT_HEADER)) {
if (msg.length != FILE_IO_TEST_RESULT_HEADER.length + 1) {
Utils.failTest('Unexpected FileIOTest CDM message' + msg);
if (Utils.hasPrefix(msg, UNIT_TEST_RESULT_HEADER)) {
if (msg.length != UNIT_TEST_RESULT_HEADER.length + 1) {
Utils.failTest('Unexpected CDM Unit Test message' + msg);
return;
}
var result_index = FILE_IO_TEST_RESULT_HEADER.length;
var result_index = UNIT_TEST_RESULT_HEADER.length;
var success = String.fromCharCode(msg[result_index]) == 1;
Utils.timeLog('CDM file IO test: ' + (success ? 'Success' : 'Fail'));
Utils.timeLog('CDM unit test: ' + (success ? 'Success' : 'Fail'));
if (success)
Utils.setResultInTitle(FILE_IO_TEST_SUCCESS);
Utils.setResultInTitle(UNIT_TEST_SUCCESS);
else
Utils.failTest('File IO CDM message fail status.');
Utils.failTest('CDM unit test failed.');
}
};
FileIOTestPlayer.prototype.onMessage = handleMessage;
UnitTestPlayer.prototype.onMessage = handleMessage;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment