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 "ui/aura/window.h"
24 #include "ui/display/chromeos/display_configurator.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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::CONTENT_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::CONTENT_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 ui::DisplayConfigurator::ContentProtectionClientId GetClientId();
101 // Used to lookup the WebContents associated with this PP_Instance.
102 int render_process_id_;
103 int render_frame_id_;
105 ui::DisplayConfigurator::ContentProtectionClientId 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_(ui::DisplayConfigurator::kInvalidClientId),
119 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
122 PepperOutputProtectionMessageFilter::Delegate::~Delegate() {
123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
125 ui::DisplayConfigurator* configurator =
126 ash::Shell::GetInstance()->display_configurator();
127 configurator->UnregisterContentProtectionClient(client_id_);
129 content::RenderFrameHost* rfh =
130 content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
132 gfx::NativeView native_view = rfh->GetNativeView();
134 native_view->RemoveObserver(this);
138 ui::DisplayConfigurator::ContentProtectionClientId
139 PepperOutputProtectionMessageFilter::Delegate::GetClientId() {
140 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
141 if (client_id_ == ui::DisplayConfigurator::kInvalidClientId) {
142 content::RenderFrameHost* rfh =
143 content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
144 if (!GetCurrentDisplayId(rfh, &display_id_))
145 return ui::DisplayConfigurator::kInvalidClientId;
146 gfx::NativeView native_view = rfh->GetNativeView();
148 return ui::DisplayConfigurator::kInvalidClientId;
149 native_view->AddObserver(this);
151 ui::DisplayConfigurator* configurator =
152 ash::Shell::GetInstance()->display_configurator();
153 client_id_ = configurator->RegisterContentProtectionClient();
158 int32_t PepperOutputProtectionMessageFilter::Delegate::OnQueryStatus(
160 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 ui::DisplayConfigurator* configurator =
171 ash::Shell::GetInstance()->display_configurator();
172 bool result = configurator->QueryContentProtectionStatus(
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)->GetCapturerCount() >
181 // Check for desktop capture.
182 MediaCaptureDevicesDispatcher::GetInstance()
183 ->IsDesktopCaptureInProgress();
184 if (capture_detected)
185 *link_mask |= ui::DISPLAY_CONNECTION_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 ui::DisplayConfigurator* configurator =
196 ash::Shell::GetInstance()->display_configurator();
197 bool result = configurator->EnableContentProtection(
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::CONTENT_PROTECTION_METHOD_NONE) {
219 // Display changed and should enable output protections on new display.
220 ui::DisplayConfigurator* configurator =
221 ash::Shell::GetInstance()->display_configurator();
222 configurator->EnableContentProtection(
223 GetClientId(), new_display_id, desired_method_mask_);
224 configurator->EnableContentProtection(
225 GetClientId(), display_id_, ui::CONTENT_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(
249 content::BrowserThread::UI, FROM_HERE, delegate_);
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(PpapiHostMsg_OutputProtection_QueryStatus,
267 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
268 PpapiHostMsg_OutputProtection_EnableProtection, OnEnableProtection);
269 IPC_END_MESSAGE_MAP()
270 return PP_ERROR_FAILED;
273 int32_t PepperOutputProtectionMessageFilter::OnQueryStatus(
274 ppapi::host::HostMessageContext* context) {
275 #if defined(OS_CHROMEOS)
276 uint32_t link_mask = 0, protection_mask = 0;
277 int32_t result = delegate_->OnQueryStatus(&link_mask, &protection_mask);
279 ppapi::host::ReplyMessageContext reply_context =
280 context->MakeReplyMessageContext();
281 reply_context.params.set_result(result);
282 SendReply(reply_context,
283 PpapiPluginMsg_OutputProtection_QueryStatusReply(link_mask,
285 return PP_OK_COMPLETIONPENDING;
288 return PP_ERROR_NOTSUPPORTED;
292 int32_t PepperOutputProtectionMessageFilter::OnEnableProtection(
293 ppapi::host::HostMessageContext* context,
294 uint32_t desired_method_mask) {
295 #if defined(OS_CHROMEOS)
296 ppapi::host::ReplyMessageContext reply_context =
297 context->MakeReplyMessageContext();
298 int32_t result = delegate_->OnEnableProtection(desired_method_mask);
299 reply_context.params.set_result(result);
300 SendReply(reply_context,
301 PpapiPluginMsg_OutputProtection_EnableProtectionReply());
302 return PP_OK_COMPLETIONPENDING;
305 return PP_ERROR_NOTSUPPORTED;
309 } // namespace chrome