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.
5 #include "chrome/browser/renderer_host/pepper/pepper_output_protection_message_filter.h"
7 #include "build/build_config.h"
8 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
9 #include "content/public/browser/browser_ppapi_host.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_frame_host.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"
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"
32 #if defined(OS_CHROMEOS)
33 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE) ==
34 static_cast<int>(ui::OUTPUT_TYPE_NONE),
35 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE);
37 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN) ==
38 static_cast<int>(ui::OUTPUT_TYPE_UNKNOWN),
39 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN);
41 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL) ==
42 static_cast<int>(ui::OUTPUT_TYPE_INTERNAL),
43 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL);
44 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA) ==
45 static_cast<int>(ui::OUTPUT_TYPE_VGA),
46 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA);
47 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI) ==
48 static_cast<int>(ui::OUTPUT_TYPE_HDMI),
49 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI);
50 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI) ==
51 static_cast<int>(ui::OUTPUT_TYPE_DVI),
52 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI);
54 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT) ==
55 static_cast<int>(ui::OUTPUT_TYPE_DISPLAYPORT),
56 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT);
58 static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK) ==
59 static_cast<int>(ui::OUTPUT_TYPE_NETWORK),
60 PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK);
61 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE) ==
62 static_cast<int>(ui::OUTPUT_PROTECTION_METHOD_NONE),
63 PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE);
64 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP) ==
65 static_cast<int>(ui::OUTPUT_PROTECTION_METHOD_HDCP),
66 PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP);
68 bool GetCurrentDisplayId(content::RenderFrameHost* rfh, int64* display_id) {
69 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
70 gfx::NativeView native_view = rfh->GetNativeView();
71 gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view);
74 gfx::Display display = screen->GetDisplayNearestWindow(native_view);
75 *display_id = display.id();
82 #if defined(OS_CHROMEOS)
83 // Output protection delegate. All methods except constructor should be
84 // invoked in UI thread.
85 class PepperOutputProtectionMessageFilter::Delegate
86 : public aura::WindowObserver {
88 Delegate(int render_process_id, int render_frame_id);
91 // aura::WindowObserver overrides.
92 virtual void OnWindowHierarchyChanged(
93 const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE;
95 int32_t OnQueryStatus(uint32_t* link_mask, uint32_t* protection_mask);
96 int32_t OnEnableProtection(uint32_t desired_method_mask);
99 chromeos::OutputConfigurator::OutputProtectionClientId GetClientId();
101 // Used to lookup the WebContents associated with this PP_Instance.
102 int render_process_id_;
103 int render_frame_id_;
105 chromeos::OutputConfigurator::OutputProtectionClientId client_id_;
106 // The display id which the renderer currently uses.
108 // The last desired method mask. Will enable this mask on new display if
109 // renderer changes display.
110 uint32_t desired_method_mask_;
113 PepperOutputProtectionMessageFilter::Delegate::Delegate(int render_process_id,
115 : render_process_id_(render_process_id),
116 render_frame_id_(render_frame_id),
117 client_id_(chromeos::OutputConfigurator::kInvalidClientId),
119 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
123 PepperOutputProtectionMessageFilter::Delegate::~Delegate() {
124 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
126 chromeos::OutputConfigurator* configurator =
127 ash::Shell::GetInstance()->output_configurator();
128 configurator->UnregisterOutputProtectionClient(client_id_);
130 content::RenderFrameHost* rfh =
131 content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
133 gfx::NativeView native_view = rfh->GetNativeView();
135 native_view->RemoveObserver(this);
139 chromeos::OutputConfigurator::OutputProtectionClientId
140 PepperOutputProtectionMessageFilter::Delegate::GetClientId() {
141 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
142 if (client_id_ == chromeos::OutputConfigurator::kInvalidClientId) {
143 content::RenderFrameHost* rfh =
144 content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
145 if (!GetCurrentDisplayId(rfh, &display_id_))
146 return chromeos::OutputConfigurator::kInvalidClientId;
147 gfx::NativeView native_view = rfh->GetNativeView();
149 return chromeos::OutputConfigurator::kInvalidClientId;
150 native_view->AddObserver(this);
152 chromeos::OutputConfigurator* configurator =
153 ash::Shell::GetInstance()->output_configurator();
154 client_id_ = configurator->RegisterOutputProtectionClient();
159 int32_t PepperOutputProtectionMessageFilter::Delegate::OnQueryStatus(
160 uint32_t* link_mask, uint32_t* protection_mask) {
161 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
163 content::RenderFrameHost* rfh =
164 content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
166 LOG(WARNING) << "RenderFrameHost is not alive.";
167 return PP_ERROR_FAILED;
170 chromeos::OutputConfigurator* configurator =
171 ash::Shell::GetInstance()->output_configurator();
172 bool result = configurator->QueryOutputProtectionStatus(
173 GetClientId(), display_id_, link_mask, protection_mask);
175 // If we successfully retrieved the device level status, check for capturers.
177 const bool capture_detected =
178 // Check for tab capture on the current tab.
179 content::WebContents::FromRenderFrameHost(rfh)->
180 GetCapturerCount() > 0 ||
181 // Check for desktop capture.
182 MediaCaptureDevicesDispatcher::GetInstance()
183 ->IsDesktopCaptureInProgress();
184 if (capture_detected)
185 *link_mask |= ui::OUTPUT_TYPE_NETWORK;
188 return result ? PP_OK : PP_ERROR_FAILED;
191 int32_t PepperOutputProtectionMessageFilter::Delegate::OnEnableProtection(
192 uint32_t desired_method_mask) {
193 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
195 chromeos::OutputConfigurator* configurator =
196 ash::Shell::GetInstance()->output_configurator();
197 bool result = configurator->EnableOutputProtection(
198 GetClientId(), display_id_, desired_method_mask);
199 desired_method_mask_ = desired_method_mask;
200 return result ? PP_OK : PP_ERROR_FAILED;
203 void PepperOutputProtectionMessageFilter::Delegate::OnWindowHierarchyChanged(
204 const aura::WindowObserver::HierarchyChangeParams& params) {
205 content::RenderFrameHost* rfh =
206 content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
208 LOG(WARNING) << "RenderFrameHost is not alive.";
212 int64 new_display_id = 0;
213 if (!GetCurrentDisplayId(rfh, &new_display_id))
215 if (display_id_ == new_display_id)
218 if (desired_method_mask_ != ui::OUTPUT_PROTECTION_METHOD_NONE) {
219 // Display changed and should enable output protections on new display.
220 chromeos::OutputConfigurator* configurator =
221 ash::Shell::GetInstance()->output_configurator();
222 configurator->EnableOutputProtection(GetClientId(), new_display_id,
223 desired_method_mask_);
224 configurator->EnableOutputProtection(
225 GetClientId(), display_id_, ui::OUTPUT_PROTECTION_METHOD_NONE);
227 display_id_ = new_display_id;
231 PepperOutputProtectionMessageFilter::PepperOutputProtectionMessageFilter(
232 content::BrowserPpapiHost* host,
233 PP_Instance instance) {
234 #if defined(OS_CHROMEOS)
235 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
236 int render_process_id = 0;
237 int render_frame_id = 0;
238 host->GetRenderFrameIDsForInstance(
239 instance, &render_process_id, &render_frame_id);
240 delegate_ = new Delegate(render_process_id, render_frame_id);
246 PepperOutputProtectionMessageFilter::~PepperOutputProtectionMessageFilter() {
247 #if defined(OS_CHROMEOS)
248 content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE,
254 scoped_refptr<base::TaskRunner>
255 PepperOutputProtectionMessageFilter::OverrideTaskRunnerForMessage(
256 const IPC::Message& message) {
257 return content::BrowserThread::GetMessageLoopProxyForThread(
258 content::BrowserThread::UI);
261 int32_t PepperOutputProtectionMessageFilter::OnResourceMessageReceived(
262 const IPC::Message& msg,
263 ppapi::host::HostMessageContext* context) {
264 IPC_BEGIN_MESSAGE_MAP(PepperOutputProtectionMessageFilter, msg)
265 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
266 PpapiHostMsg_OutputProtection_QueryStatus,
268 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
269 PpapiHostMsg_OutputProtection_EnableProtection,
271 IPC_END_MESSAGE_MAP()
272 return PP_ERROR_FAILED;
275 int32_t PepperOutputProtectionMessageFilter::OnQueryStatus(
276 ppapi::host::HostMessageContext* context) {
277 #if defined(OS_CHROMEOS)
278 uint32_t link_mask = 0, protection_mask = 0;
279 int32_t result = delegate_->OnQueryStatus(&link_mask, &protection_mask);
281 ppapi::host::ReplyMessageContext reply_context =
282 context->MakeReplyMessageContext();
283 reply_context.params.set_result(result);
286 PpapiPluginMsg_OutputProtection_QueryStatusReply(
287 link_mask, protection_mask));
288 return PP_OK_COMPLETIONPENDING;
291 return PP_ERROR_NOTSUPPORTED;
295 int32_t PepperOutputProtectionMessageFilter::OnEnableProtection(
296 ppapi::host::HostMessageContext* context,
297 uint32_t desired_method_mask) {
298 #if defined(OS_CHROMEOS)
299 ppapi::host::ReplyMessageContext reply_context =
300 context->MakeReplyMessageContext();
301 int32_t result = delegate_->OnEnableProtection(desired_method_mask);
302 reply_context.params.set_result(result);
305 PpapiPluginMsg_OutputProtection_EnableProtectionReply());
306 return PP_OK_COMPLETIONPENDING;
309 return PP_ERROR_NOTSUPPORTED;
313 } // namespace chrome