diff options
5 files changed, 307 insertions, 120 deletions
diff --git a/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.cc index 10dc050..ef7a27e 100644 --- a/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.cc +++ b/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.cc @@ -8,6 +8,7 @@ #include "content/public/browser/browser_ppapi_host.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_output_protection_private.h" @@ -16,10 +17,12 @@ #include "ppapi/host/ppapi_host.h" #include "ppapi/proxy/ppapi_messages.h" -#if defined(USE_ASH) && defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) #include "ash/shell.h" #include "ash/shell_delegate.h" #include "chromeos/display/output_configurator.h" +#include "ui/aura/window.h" +#include "ui/gfx/screen.h" #endif namespace chrome { @@ -67,40 +70,193 @@ COMPILE_ASSERT( static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP) == static_cast<int>(chromeos::OUTPUT_PROTECTION_METHOD_HDCP), PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP); + +bool GetCurrentDisplayId(content::RenderViewHost* rvh, int64* display_id) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + content::RenderWidgetHostView* view = rvh->GetView(); + if (!view) + return false; + gfx::NativeView native_view = view->GetNativeView(); + gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); + if (!screen) + return false; + gfx::Display display = screen->GetDisplayNearestWindow(native_view); + *display_id = display.id(); + return true; +} #endif -#if defined(OS_CHROMEOS) && defined(USE_ASH) -void UnregisterClientOnUIThread( - chromeos::OutputConfigurator::OutputProtectionClientId client_id) { +} // namespace + +#if defined(OS_CHROMEOS) +// Output protection delegate. All methods except constructor should be +// invoked in UI thread. +class PepperOutputProtectionMessageFilter::Delegate + : public aura::WindowObserver { + public: + Delegate(int render_process_id, int render_view_id); + virtual ~Delegate(); + + // aura::WindowObserver overrides. + virtual void OnWindowHierarchyChanged( + const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE; + + int32_t OnQueryStatus(uint32_t* link_mask, uint32_t* protection_mask); + int32_t OnEnableProtection(uint32_t desired_method_mask); + + private: + chromeos::OutputConfigurator::OutputProtectionClientId GetClientId(); + + // Used to lookup the WebContents associated with this PP_Instance. + int render_process_id_; + int render_view_id_; + + chromeos::OutputConfigurator::OutputProtectionClientId client_id_; + // The display id which the renderer currently uses. + int64 display_id_; + // The last desired method mask. Will enable this mask on new display if + // renderer changes display. + uint32_t desired_method_mask_; +}; + +PepperOutputProtectionMessageFilter::Delegate::Delegate(int render_process_id, + int render_view_id) + : render_process_id_(render_process_id), + render_view_id_(render_view_id), + client_id_(chromeos::OutputConfigurator::kInvalidClientId), + display_id_(0) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + +} + +PepperOutputProtectionMessageFilter::Delegate::~Delegate() { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + chromeos::OutputConfigurator* configurator = ash::Shell::GetInstance()->output_configurator(); - configurator->UnregisterOutputProtectionClient(client_id); + configurator->UnregisterOutputProtectionClient(client_id_); + + content::RenderViewHost* rvh = + content::RenderViewHost::FromID(render_process_id_, render_view_id_); + if (rvh) { + content::RenderWidgetHostView* view = rvh->GetView(); + if (view) { + gfx::NativeView native_view = view->GetNativeView(); + native_view->RemoveObserver(this); + } + } } -#endif -} // namespace +chromeos::OutputConfigurator::OutputProtectionClientId +PepperOutputProtectionMessageFilter::Delegate::GetClientId() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (client_id_ == chromeos::OutputConfigurator::kInvalidClientId) { + content::RenderViewHost* rvh = + content::RenderViewHost::FromID(render_process_id_, render_view_id_); + if (!GetCurrentDisplayId(rvh, &display_id_)) + return chromeos::OutputConfigurator::kInvalidClientId; + content::RenderWidgetHostView* view = rvh->GetView(); + if (!view) + return chromeos::OutputConfigurator::kInvalidClientId; + gfx::NativeView native_view = view->GetNativeView(); + if (!view) + return chromeos::OutputConfigurator::kInvalidClientId; + native_view->AddObserver(this); + + chromeos::OutputConfigurator* configurator = + ash::Shell::GetInstance()->output_configurator(); + client_id_ = configurator->RegisterOutputProtectionClient(); + } + return client_id_; +} + +int32_t PepperOutputProtectionMessageFilter::Delegate::OnQueryStatus( + uint32_t* link_mask, uint32_t* protection_mask) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + content::RenderViewHost* rvh = + content::RenderViewHost::FromID(render_process_id_, render_view_id_); + if (!rvh) { + LOG(WARNING) << "RenderViewHost is not alive."; + return PP_ERROR_FAILED; + } + + chromeos::OutputConfigurator* configurator = + ash::Shell::GetInstance()->output_configurator(); + bool result = configurator->QueryOutputProtectionStatus( + GetClientId(), display_id_, link_mask, protection_mask); + + // If we successfully retrieved the device level status, check for capturers. + if (result) { + if (content::WebContents::FromRenderViewHost(rvh)->GetCapturerCount() > 0) + *link_mask |= chromeos::OUTPUT_TYPE_NETWORK; + } + + return PP_OK; +} + +int32_t PepperOutputProtectionMessageFilter::Delegate::OnEnableProtection( + uint32_t desired_method_mask) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + chromeos::OutputConfigurator* configurator = + ash::Shell::GetInstance()->output_configurator(); + bool result = configurator->EnableOutputProtection( + GetClientId(), display_id_, desired_method_mask); + desired_method_mask_ = desired_method_mask; + return result ? PP_OK : PP_ERROR_FAILED; +} + +void PepperOutputProtectionMessageFilter::Delegate::OnWindowHierarchyChanged( + const aura::WindowObserver::HierarchyChangeParams& params) { + content::RenderViewHost* rvh = + content::RenderViewHost::FromID(render_process_id_, render_view_id_); + if (!rvh) { + LOG(WARNING) << "RenderViewHost is not alive."; + return; + } + + int64 new_display_id = 0; + if (!GetCurrentDisplayId(rvh, &new_display_id)) + return; + if (display_id_ == new_display_id) + return; + + if (desired_method_mask_ != chromeos::OUTPUT_PROTECTION_METHOD_NONE) { + // Display changed and should enable output protections on new display. + chromeos::OutputConfigurator* configurator = + ash::Shell::GetInstance()->output_configurator(); + configurator->EnableOutputProtection(GetClientId(), new_display_id, + desired_method_mask_); + configurator->EnableOutputProtection( + GetClientId(), + display_id_, + chromeos::OUTPUT_PROTECTION_METHOD_NONE); + } + display_id_ = new_display_id; +} +#endif PepperOutputProtectionMessageFilter::PepperOutputProtectionMessageFilter( content::BrowserPpapiHost* host, PP_Instance instance) { -#if defined(OS_CHROMEOS) && defined(USE_ASH) && defined(USE_X11) - client_id_ = 0; +#if defined(OS_CHROMEOS) + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + int render_process_id = 0; + int render_view_id = 0; host->GetRenderViewIDsForInstance( - instance, &render_process_id_, &render_view_id_); + instance, &render_process_id, &render_view_id); + delegate_ = new Delegate(render_process_id, render_view_id); #else NOTIMPLEMENTED(); #endif } PepperOutputProtectionMessageFilter::~PepperOutputProtectionMessageFilter() { -#if defined(OS_CHROMEOS) && defined(USE_ASH) - if (client_id_ != 0) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&UnregisterClientOnUIThread, client_id_)); - } +#if defined(OS_CHROMEOS) + content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE, + delegate_); + delegate_ = NULL; #endif } @@ -125,46 +281,15 @@ int32_t PepperOutputProtectionMessageFilter::OnResourceMessageReceived( return PP_ERROR_FAILED; } -#if defined(OS_CHROMEOS) -chromeos::OutputConfigurator::OutputProtectionClientId -PepperOutputProtectionMessageFilter::GetClientId() { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - if (client_id_ == 0) { -#if defined(USE_ASH) && defined(USE_X11) - chromeos::OutputConfigurator* configurator = - ash::Shell::GetInstance()->output_configurator(); - client_id_ = configurator->RegisterOutputProtectionClient(); -#endif - } - return client_id_; -} -#endif - int32_t PepperOutputProtectionMessageFilter::OnQueryStatus( ppapi::host::HostMessageContext* context) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); +#if defined(OS_CHROMEOS) + uint32_t link_mask = 0, protection_mask = 0; + int32_t result = delegate_->OnQueryStatus(&link_mask, &protection_mask); -#if defined(OS_CHROMEOS) && defined(USE_ASH) && defined(USE_X11) ppapi::host::ReplyMessageContext reply_context = context->MakeReplyMessageContext(); - uint32_t link_mask = 0, protection_mask = 0; - chromeos::OutputConfigurator* configurator = - ash::Shell::GetInstance()->output_configurator(); - bool result = configurator->QueryOutputProtectionStatus( - GetClientId(), &link_mask, &protection_mask); - - // If we successfully retrieved the device level status, check for capturers. - if (result) { - // Ensure the RenderViewHost is still alive. - content::RenderViewHost* rvh = - content::RenderViewHost::FromID(render_process_id_, render_view_id_); - if (rvh) { - if (content::WebContents::FromRenderViewHost(rvh)->GetCapturerCount() > 0) - link_mask |= chromeos::OUTPUT_TYPE_NETWORK; - } - } - - reply_context.params.set_result(result ? PP_OK : PP_ERROR_FAILED); + reply_context.params.set_result(result); SendReply( reply_context, PpapiPluginMsg_OutputProtection_QueryStatusReply( @@ -179,16 +304,11 @@ int32_t PepperOutputProtectionMessageFilter::OnQueryStatus( int32_t PepperOutputProtectionMessageFilter::OnEnableProtection( ppapi::host::HostMessageContext* context, uint32_t desired_method_mask) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - -#if defined(OS_CHROMEOS) && defined(USE_ASH) && defined(USE_X11) +#if defined(OS_CHROMEOS) ppapi::host::ReplyMessageContext reply_context = context->MakeReplyMessageContext(); - chromeos::OutputConfigurator* configurator = - ash::Shell::GetInstance()->output_configurator(); - bool result = configurator->EnableOutputProtection( - GetClientId(), desired_method_mask); - reply_context.params.set_result(result ? PP_OK : PP_ERROR_FAILED); + int32_t result = delegate_->OnEnableProtection(desired_method_mask); + reply_context.params.set_result(result); SendReply( reply_context, PpapiPluginMsg_OutputProtection_EnableProtectionReply()); diff --git a/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h b/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h index be5ef16..6994d85 100644 --- a/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h +++ b/chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h @@ -31,6 +31,10 @@ class PepperOutputProtectionMessageFilter PP_Instance instance); private: +#if defined(OS_CHROMEOS) + class Delegate; +#endif + // ppapi::host::ResourceMessageFilter overrides. virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage( const IPC::Message& msg) OVERRIDE; @@ -40,19 +44,13 @@ class PepperOutputProtectionMessageFilter virtual ~PepperOutputProtectionMessageFilter(); -#if defined(OS_CHROMEOS) - chromeos::OutputConfigurator::OutputProtectionClientId GetClientId(); -#endif int32_t OnQueryStatus(ppapi::host::HostMessageContext* context); int32_t OnEnableProtection(ppapi::host::HostMessageContext* context, uint32_t desired_method_mask); #if defined(OS_CHROMEOS) - chromeos::OutputConfigurator::OutputProtectionClientId client_id_; - - // Used to lookup the WebContents associated with this PP_Instance. - int render_process_id_; - int render_view_id_; + // Delegator. Should be deleted in UI thread. + Delegate* delegate_; #endif DISALLOW_COPY_AND_ASSIGN(PepperOutputProtectionMessageFilter); diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc index 4676246..1a3cc31 100644 --- a/chromeos/display/output_configurator.cc +++ b/chromeos/display/output_configurator.cc @@ -299,21 +299,72 @@ void OutputConfigurator::Start(uint32 background_color_argb) { NotifyObservers(success, new_state); } +bool OutputConfigurator::ApplyProtections(const DisplayProtections& requests) { + for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); + it != cached_outputs_.end(); ++it) { + RROutput this_id = it->output; + uint32_t all_desired = 0; + DisplayProtections::const_iterator request_it = requests.find( + it->display_id); + if (request_it != requests.end()) + all_desired = request_it->second; + switch (it->type) { + case OUTPUT_TYPE_UNKNOWN: + return false; + // DisplayPort, DVI, and HDMI all support HDCP. + case OUTPUT_TYPE_DISPLAYPORT: + case OUTPUT_TYPE_DVI: + case OUTPUT_TYPE_HDMI: { + HDCPState new_desired_state = + (all_desired & OUTPUT_PROTECTION_METHOD_HDCP) ? + HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED; + if (!delegate_->SetHDCPState(this_id, new_desired_state)) + return false; + break; + } + case OUTPUT_TYPE_INTERNAL: + case OUTPUT_TYPE_VGA: + case OUTPUT_TYPE_NETWORK: + // No protections for these types. Do nothing. + break; + case OUTPUT_TYPE_NONE: + NOTREACHED(); + break; + } + } + + return true; +} + OutputConfigurator::OutputProtectionClientId OutputConfigurator::RegisterOutputProtectionClient() { if (!configure_display_) - return 0; + return kInvalidClientId; return next_output_protection_client_id_++; } void OutputConfigurator::UnregisterOutputProtectionClient( OutputProtectionClientId client_id) { - EnableOutputProtection(client_id, OUTPUT_PROTECTION_METHOD_NONE); + client_protection_requests_.erase(client_id); + + DisplayProtections protections; + for (ProtectionRequests::const_iterator it = + client_protection_requests_.begin(); + it != client_protection_requests_.end(); + ++it) { + for (DisplayProtections::const_iterator it2 = it->second.begin(); + it2 != it->second.end(); ++it2) { + protections[it2->first] |= it2->second; + } + } + + ApplyProtections(protections); } bool OutputConfigurator::QueryOutputProtectionStatus( OutputProtectionClientId client_id, + int64 display_id, uint32_t* link_mask, uint32_t* protection_mask) { if (!configure_display_) @@ -325,6 +376,8 @@ bool OutputConfigurator::QueryOutputProtectionStatus( for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); it != cached_outputs_.end(); ++it) { RROutput this_id = it->output; + if (it->display_id != display_id) + continue; *link_mask |= it->type; switch (it->type) { case OUTPUT_TYPE_UNKNOWN: @@ -356,7 +409,9 @@ bool OutputConfigurator::QueryOutputProtectionStatus( // Don't reveal protections requested by other clients. ProtectionRequests::iterator it = client_protection_requests_.find(client_id); if (it != client_protection_requests_.end()) { - uint32_t requested_mask = it->second; + uint32_t requested_mask = 0; + if (it->second.find(display_id) != it->second.end()) + requested_mask = it->second[display_id]; *protection_mask = enabled & ~unfulfilled & requested_mask; } else { *protection_mask = 0; @@ -366,52 +421,39 @@ bool OutputConfigurator::QueryOutputProtectionStatus( bool OutputConfigurator::EnableOutputProtection( OutputProtectionClientId client_id, + int64 display_id, uint32_t desired_method_mask) { if (!configure_display_) return false; - uint32_t all_desired = desired_method_mask; + DisplayProtections protections; for (ProtectionRequests::const_iterator it = client_protection_requests_.begin(); it != client_protection_requests_.end(); ++it) { - if (it->first != client_id) - all_desired |= it->second; + for (DisplayProtections::const_iterator it2 = it->second.begin(); + it2 != it->second.end(); ++it2) { + if (it->first == client_id && it2->first == display_id) + continue; + protections[it2->first] |= it2->second; + } } + protections[display_id] |= desired_method_mask; - for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin(); - it != cached_outputs_.end(); ++it) { - RROutput this_id = it->output; - switch (it->type) { - case OUTPUT_TYPE_UNKNOWN: - return false; - // DisplayPort, DVI, and HDMI all support HDCP. - case OUTPUT_TYPE_DISPLAYPORT: - case OUTPUT_TYPE_DVI: - case OUTPUT_TYPE_HDMI: { - HDCPState new_desired_state = - (all_desired & OUTPUT_PROTECTION_METHOD_HDCP) ? - HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED; - if (!delegate_->SetHDCPState(this_id, new_desired_state)) - return false; - break; - } - case OUTPUT_TYPE_INTERNAL: - case OUTPUT_TYPE_VGA: - case OUTPUT_TYPE_NETWORK: - // No protections for these types. Do nothing. - break; - case OUTPUT_TYPE_NONE: - NOTREACHED(); - break; + if (!ApplyProtections(protections)) + return false; + + if (desired_method_mask == OUTPUT_PROTECTION_METHOD_NONE) { + if (client_protection_requests_.find(client_id) != + client_protection_requests_.end()) { + client_protection_requests_[client_id].erase(display_id); + if (client_protection_requests_[client_id].size() == 0) + client_protection_requests_.erase(client_id); } + } else { + client_protection_requests_[client_id][display_id] = desired_method_mask; } - if (desired_method_mask == OUTPUT_PROTECTION_METHOD_NONE) - client_protection_requests_.erase(client_id); - else - client_protection_requests_[client_id] = desired_method_mask; - return true; } diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h index 3491344..ef5085e 100644 --- a/chromeos/display/output_configurator.h +++ b/chromeos/display/output_configurator.h @@ -68,6 +68,7 @@ class CHROMEOS_EXPORT OutputConfigurator public base::MessagePumpObserver { public: typedef uint64_t OutputProtectionClientId; + static const OutputProtectionClientId kInvalidClientId = 0; struct ModeInfo { ModeInfo(); @@ -413,6 +414,7 @@ class CHROMEOS_EXPORT OutputConfigurator // Returns true on success. bool QueryOutputProtectionStatus( OutputProtectionClientId client_id, + int64 display_id, uint32_t* link_mask, uint32_t* protection_mask); @@ -422,12 +424,15 @@ class CHROMEOS_EXPORT OutputConfigurator // Returns true when the protection request has been made. bool EnableOutputProtection( OutputProtectionClientId client_id, + int64 display_id, uint32_t desired_protection_mask); private: - // Mapping a client to its protection request bitmask. - typedef std::map<chromeos::OutputConfigurator::OutputProtectionClientId, - uint32_t> ProtectionRequests; + // Mapping a display_id to a protection request bitmask. + typedef std::map<int64, uint32_t> DisplayProtections; + // Mapping a client to its protection request. + typedef std::map<OutputProtectionClientId, + DisplayProtections> ProtectionRequests; // Updates |cached_outputs_| to contain currently-connected outputs. Calls // |delegate_->GetOutputs()| and then does additional work, like finding the @@ -487,6 +492,9 @@ class CHROMEOS_EXPORT OutputConfigurator float GetMirroredDisplayAreaRatio( const OutputConfigurator::OutputSnapshot& output); + // Applies output protections according to requests. + bool ApplyProtections(const DisplayProtections& requests); + StateController* state_controller_; SoftwareMirroringController* mirroring_controller_; scoped_ptr<Delegate> delegate_; diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc index 4e23345..28f0553 100644 --- a/chromeos/display/output_configurator_unittest.cc +++ b/chromeos/display/output_configurator_unittest.cc @@ -358,6 +358,7 @@ class OutputConfiguratorTest : public testing::Test { o->is_aspect_preserving_scaling = true; o->mode_infos[kSmallModeId] = small_mode_info; o->has_display_id = true; + o->display_id = 123; o->index = 0; o = &outputs_[1]; @@ -371,6 +372,7 @@ class OutputConfiguratorTest : public testing::Test { o->mode_infos[kSmallModeId] = small_mode_info; o->mode_infos[kBigModeId] = big_mode_info; o->has_display_id = true; + o->display_id = 456; o->index = 1; UpdateOutputs(2, false); @@ -1120,7 +1122,9 @@ TEST_F(OutputConfiguratorTest, OutputProtection) { EXPECT_NE(kNoActions, delegate_->GetActionsAndClear()); uint32_t link_mask = 0; uint32_t protection_mask = 0; - EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, &link_mask, + EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, + outputs_[0].display_id, + &link_mask, &protection_mask)); EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask); EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE), @@ -1130,28 +1134,38 @@ TEST_F(OutputConfiguratorTest, OutputProtection) { // Two outputs. UpdateOutputs(2, true); EXPECT_NE(kNoActions, delegate_->GetActionsAndClear()); - EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, &link_mask, + EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, + outputs_[1].display_id, + &link_mask, &protection_mask)); - EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL | OUTPUT_TYPE_HDMI), + EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE), protection_mask); EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); EXPECT_TRUE( - configurator_.EnableOutputProtection(id, OUTPUT_PROTECTION_METHOD_HDCP)); + configurator_.EnableOutputProtection(id, + outputs_[1].display_id, + OUTPUT_PROTECTION_METHOD_HDCP)); EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED), delegate_->GetActionsAndClear()); // Enable protection. delegate_->set_hdcp_state(HDCP_STATE_ENABLED); - EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, &link_mask, + EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id, + outputs_[1].display_id, + &link_mask, &protection_mask)); - EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL | OUTPUT_TYPE_HDMI), - link_mask); + EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP), protection_mask); EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear()); + + // Protections should be disabled after unregister. + configurator_.UnregisterOutputProtectionClient(id); + EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED), + delegate_->GetActionsAndClear()); } TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) { @@ -1169,6 +1183,7 @@ TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) { // Clients never know state enableness for methods that they didn't request. EXPECT_TRUE( configurator_.EnableOutputProtection(client1, + outputs_[1].display_id, OUTPUT_PROTECTION_METHOD_HDCP)); EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED).c_str(), @@ -1177,27 +1192,31 @@ TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) { uint32_t link_mask = 0; uint32_t protection_mask = 0; - EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1, &link_mask, + EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1, + outputs_[1].display_id, + &link_mask, &protection_mask)); - EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL | OUTPUT_TYPE_HDMI), - link_mask); + EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); EXPECT_EQ(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask); - EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2, &link_mask, + EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2, + outputs_[1].display_id, + &link_mask, &protection_mask)); - EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL | OUTPUT_TYPE_HDMI), - link_mask); + EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask); EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask); // Protections will be disabled only if no more clients request them. EXPECT_TRUE( configurator_.EnableOutputProtection(client2, + outputs_[1].display_id, OUTPUT_PROTECTION_METHOD_NONE)); EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED).c_str(), delegate_->GetActionsAndClear()); EXPECT_TRUE( configurator_.EnableOutputProtection(client1, + outputs_[1].display_id, OUTPUT_PROTECTION_METHOD_NONE)); EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED).c_str(), |