pepper_output_protection_message_filter.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h" 6 7#include "build/build_config.h" 8#include "content/public/browser/browser_ppapi_host.h" 9#include "content/public/browser/browser_thread.h" 10#include "content/public/browser/render_view_host.h" 11#include "content/public/browser/render_widget_host_view.h" 12#include "content/public/browser/web_contents.h" 13#include "ppapi/c/pp_errors.h" 14#include "ppapi/c/private/ppb_output_protection_private.h" 15#include "ppapi/host/dispatch_host_message.h" 16#include "ppapi/host/host_message_context.h" 17#include "ppapi/host/ppapi_host.h" 18#include "ppapi/proxy/ppapi_messages.h" 19 20#if defined(OS_CHROMEOS) 21#include "ash/shell.h" 22#include "ash/shell_delegate.h" 23#include "chromeos/display/output_configurator.h" 24#include "ui/aura/window.h" 25#include "ui/gfx/screen.h" 26#endif 27 28namespace chrome { 29 30namespace { 31 32#if defined(OS_CHROMEOS) 33COMPILE_ASSERT( 34 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE) == 35 static_cast<int>(chromeos::OUTPUT_TYPE_NONE), 36 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE); 37COMPILE_ASSERT( 38 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN) == 39 static_cast<int>(chromeos::OUTPUT_TYPE_UNKNOWN), 40 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN); 41COMPILE_ASSERT( 42 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL) == 43 static_cast<int>(chromeos::OUTPUT_TYPE_INTERNAL), 44 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL); 45COMPILE_ASSERT( 46 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA) == 47 static_cast<int>(chromeos::OUTPUT_TYPE_VGA), 48 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA); 49COMPILE_ASSERT( 50 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI) == 51 static_cast<int>(chromeos::OUTPUT_TYPE_HDMI), 52 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI); 53COMPILE_ASSERT( 54 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI) == 55 static_cast<int>(chromeos::OUTPUT_TYPE_DVI), 56 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI); 57COMPILE_ASSERT( 58 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT) == 59 static_cast<int>(chromeos::OUTPUT_TYPE_DISPLAYPORT), 60 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT); 61COMPILE_ASSERT( 62 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK) == 63 static_cast<int>(chromeos::OUTPUT_TYPE_NETWORK), 64 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK); 65COMPILE_ASSERT( 66 static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE) == 67 static_cast<int>(chromeos::OUTPUT_PROTECTION_METHOD_NONE), 68 PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE); 69COMPILE_ASSERT( 70 static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP) == 71 static_cast<int>(chromeos::OUTPUT_PROTECTION_METHOD_HDCP), 72 PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP); 73 74bool GetCurrentDisplayId(content::RenderViewHost* rvh, int64* display_id) { 75 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 76 content::RenderWidgetHostView* view = rvh->GetView(); 77 if (!view) 78 return false; 79 gfx::NativeView native_view = view->GetNativeView(); 80 gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); 81 if (!screen) 82 return false; 83 gfx::Display display = screen->GetDisplayNearestWindow(native_view); 84 *display_id = display.id(); 85 return true; 86} 87#endif 88 89} // namespace 90 91#if defined(OS_CHROMEOS) 92// Output protection delegate. All methods except constructor should be 93// invoked in UI thread. 94class PepperOutputProtectionMessageFilter::Delegate 95 : public aura::WindowObserver { 96 public: 97 Delegate(int render_process_id, int render_view_id); 98 virtual ~Delegate(); 99 100 // aura::WindowObserver overrides. 101 virtual void OnWindowHierarchyChanged( 102 const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE; 103 104 int32_t OnQueryStatus(uint32_t* link_mask, uint32_t* protection_mask); 105 int32_t OnEnableProtection(uint32_t desired_method_mask); 106 107 private: 108 chromeos::OutputConfigurator::OutputProtectionClientId GetClientId(); 109 110 // Used to lookup the WebContents associated with this PP_Instance. 111 int render_process_id_; 112 int render_view_id_; 113 114 chromeos::OutputConfigurator::OutputProtectionClientId client_id_; 115 // The display id which the renderer currently uses. 116 int64 display_id_; 117 // The last desired method mask. Will enable this mask on new display if 118 // renderer changes display. 119 uint32_t desired_method_mask_; 120}; 121 122PepperOutputProtectionMessageFilter::Delegate::Delegate(int render_process_id, 123 int render_view_id) 124 : render_process_id_(render_process_id), 125 render_view_id_(render_view_id), 126 client_id_(chromeos::OutputConfigurator::kInvalidClientId), 127 display_id_(0) { 128 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 129 130} 131 132PepperOutputProtectionMessageFilter::Delegate::~Delegate() { 133 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 134 135 chromeos::OutputConfigurator* configurator = 136 ash::Shell::GetInstance()->output_configurator(); 137 configurator->UnregisterOutputProtectionClient(client_id_); 138 139 content::RenderViewHost* rvh = 140 content::RenderViewHost::FromID(render_process_id_, render_view_id_); 141 if (rvh) { 142 content::RenderWidgetHostView* view = rvh->GetView(); 143 if (view) { 144 gfx::NativeView native_view = view->GetNativeView(); 145 native_view->RemoveObserver(this); 146 } 147 } 148} 149 150chromeos::OutputConfigurator::OutputProtectionClientId 151PepperOutputProtectionMessageFilter::Delegate::GetClientId() { 152 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 153 if (client_id_ == chromeos::OutputConfigurator::kInvalidClientId) { 154 content::RenderViewHost* rvh = 155 content::RenderViewHost::FromID(render_process_id_, render_view_id_); 156 if (!GetCurrentDisplayId(rvh, &display_id_)) 157 return chromeos::OutputConfigurator::kInvalidClientId; 158 content::RenderWidgetHostView* view = rvh->GetView(); 159 if (!view) 160 return chromeos::OutputConfigurator::kInvalidClientId; 161 gfx::NativeView native_view = view->GetNativeView(); 162 if (!view) 163 return chromeos::OutputConfigurator::kInvalidClientId; 164 native_view->AddObserver(this); 165 166 chromeos::OutputConfigurator* configurator = 167 ash::Shell::GetInstance()->output_configurator(); 168 client_id_ = configurator->RegisterOutputProtectionClient(); 169 } 170 return client_id_; 171} 172 173int32_t PepperOutputProtectionMessageFilter::Delegate::OnQueryStatus( 174 uint32_t* link_mask, uint32_t* protection_mask) { 175 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 176 177 content::RenderViewHost* rvh = 178 content::RenderViewHost::FromID(render_process_id_, render_view_id_); 179 if (!rvh) { 180 LOG(WARNING) << "RenderViewHost is not alive."; 181 return PP_ERROR_FAILED; 182 } 183 184 chromeos::OutputConfigurator* configurator = 185 ash::Shell::GetInstance()->output_configurator(); 186 bool result = configurator->QueryOutputProtectionStatus( 187 GetClientId(), display_id_, link_mask, protection_mask); 188 189 // If we successfully retrieved the device level status, check for capturers. 190 if (result) { 191 if (content::WebContents::FromRenderViewHost(rvh)->GetCapturerCount() > 0) 192 *link_mask |= chromeos::OUTPUT_TYPE_NETWORK; 193 } 194 195 return result ? PP_OK : PP_ERROR_FAILED; 196} 197 198int32_t PepperOutputProtectionMessageFilter::Delegate::OnEnableProtection( 199 uint32_t desired_method_mask) { 200 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 201 202 chromeos::OutputConfigurator* configurator = 203 ash::Shell::GetInstance()->output_configurator(); 204 bool result = configurator->EnableOutputProtection( 205 GetClientId(), display_id_, desired_method_mask); 206 desired_method_mask_ = desired_method_mask; 207 return result ? PP_OK : PP_ERROR_FAILED; 208} 209 210void PepperOutputProtectionMessageFilter::Delegate::OnWindowHierarchyChanged( 211 const aura::WindowObserver::HierarchyChangeParams& params) { 212 content::RenderViewHost* rvh = 213 content::RenderViewHost::FromID(render_process_id_, render_view_id_); 214 if (!rvh) { 215 LOG(WARNING) << "RenderViewHost is not alive."; 216 return; 217 } 218 219 int64 new_display_id = 0; 220 if (!GetCurrentDisplayId(rvh, &new_display_id)) 221 return; 222 if (display_id_ == new_display_id) 223 return; 224 225 if (desired_method_mask_ != chromeos::OUTPUT_PROTECTION_METHOD_NONE) { 226 // Display changed and should enable output protections on new display. 227 chromeos::OutputConfigurator* configurator = 228 ash::Shell::GetInstance()->output_configurator(); 229 configurator->EnableOutputProtection(GetClientId(), new_display_id, 230 desired_method_mask_); 231 configurator->EnableOutputProtection( 232 GetClientId(), 233 display_id_, 234 chromeos::OUTPUT_PROTECTION_METHOD_NONE); 235 } 236 display_id_ = new_display_id; 237} 238#endif 239 240PepperOutputProtectionMessageFilter::PepperOutputProtectionMessageFilter( 241 content::BrowserPpapiHost* host, 242 PP_Instance instance) { 243#if defined(OS_CHROMEOS) 244 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 245 int render_process_id = 0; 246 int render_view_id = 0; 247 host->GetRenderViewIDsForInstance( 248 instance, &render_process_id, &render_view_id); 249 delegate_ = new Delegate(render_process_id, render_view_id); 250#else 251 NOTIMPLEMENTED(); 252#endif 253} 254 255PepperOutputProtectionMessageFilter::~PepperOutputProtectionMessageFilter() { 256#if defined(OS_CHROMEOS) 257 content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE, 258 delegate_); 259 delegate_ = NULL; 260#endif 261} 262 263scoped_refptr<base::TaskRunner> 264PepperOutputProtectionMessageFilter::OverrideTaskRunnerForMessage( 265 const IPC::Message& message) { 266 return content::BrowserThread::GetMessageLoopProxyForThread( 267 content::BrowserThread::UI); 268} 269 270int32_t PepperOutputProtectionMessageFilter::OnResourceMessageReceived( 271 const IPC::Message& msg, 272 ppapi::host::HostMessageContext* context) { 273 IPC_BEGIN_MESSAGE_MAP(PepperOutputProtectionMessageFilter, msg) 274 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( 275 PpapiHostMsg_OutputProtection_QueryStatus, 276 OnQueryStatus); 277 PPAPI_DISPATCH_HOST_RESOURCE_CALL( 278 PpapiHostMsg_OutputProtection_EnableProtection, 279 OnEnableProtection); 280 IPC_END_MESSAGE_MAP() 281 return PP_ERROR_FAILED; 282} 283 284int32_t PepperOutputProtectionMessageFilter::OnQueryStatus( 285 ppapi::host::HostMessageContext* context) { 286#if defined(OS_CHROMEOS) 287 uint32_t link_mask = 0, protection_mask = 0; 288 int32_t result = delegate_->OnQueryStatus(&link_mask, &protection_mask); 289 290 ppapi::host::ReplyMessageContext reply_context = 291 context->MakeReplyMessageContext(); 292 reply_context.params.set_result(result); 293 SendReply( 294 reply_context, 295 PpapiPluginMsg_OutputProtection_QueryStatusReply( 296 link_mask, protection_mask)); 297 return PP_OK_COMPLETIONPENDING; 298#else 299 NOTIMPLEMENTED(); 300 return PP_ERROR_NOTSUPPORTED; 301#endif 302} 303 304int32_t PepperOutputProtectionMessageFilter::OnEnableProtection( 305 ppapi::host::HostMessageContext* context, 306 uint32_t desired_method_mask) { 307#if defined(OS_CHROMEOS) 308 ppapi::host::ReplyMessageContext reply_context = 309 context->MakeReplyMessageContext(); 310 int32_t result = delegate_->OnEnableProtection(desired_method_mask); 311 reply_context.params.set_result(result); 312 SendReply( 313 reply_context, 314 PpapiPluginMsg_OutputProtection_EnableProtectionReply()); 315 return PP_OK_COMPLETIONPENDING; 316#else 317 NOTIMPLEMENTED(); 318 return PP_ERROR_NOTSUPPORTED; 319#endif 320} 321 322} // namespace chrome 323 324