| // Copyright (c) 2012 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/renderer_host/pepper/pepper_flash_drm_host.h" |
| |
| #if defined(OS_WIN) |
| #include <Windows.h> |
| #endif |
| |
| #include "base/bind.h" |
| #include "base/compiler_specific.h" |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "content/public/browser/browser_ppapi_host.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/child_process_security_policy.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/common/pepper_plugin_info.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/host/dispatch_host_message.h" |
| #include "ppapi/host/host_message_context.h" |
| #include "ppapi/host/ppapi_host.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| |
| #if defined(USE_AURA) |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_tree_host.h" |
| #endif |
| |
| #if defined(OS_MACOSX) |
| #include "chrome/browser/renderer_host/pepper/monitor_finder_mac.h" |
| #endif |
| |
| using content::BrowserPpapiHost; |
| |
| namespace chrome { |
| |
| namespace { |
| const char kVoucherFilename[] = "plugin.vch"; |
| } |
| |
| #if defined(OS_WIN) |
| // Helper class to get the UI thread which monitor is showing the |
| // window associated with the instance's render view. Since we get |
| // called by the IO thread and we cannot block, the first answer is |
| // of GetMonitor() may be NULL, but eventually it will contain the |
| // right monitor. |
| class MonitorFinder : public base::RefCountedThreadSafe<MonitorFinder> { |
| public: |
| MonitorFinder(int process_id, int render_frame_id) |
| : process_id_(process_id), |
| render_frame_id_(render_frame_id), |
| monitor_(NULL), |
| request_sent_(0) {} |
| |
| int64_t GetMonitor() { |
| // We use |request_sent_| as an atomic boolean so that we |
| // never have more than one task posted at a given time. We |
| // do this because we don't know how often our client is going |
| // to call and we can't cache the |monitor_| value. |
| if (InterlockedCompareExchange(&request_sent_, 1, 0) == 0) { |
| content::BrowserThread::PostTask( |
| content::BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(&MonitorFinder::FetchMonitorFromWidget, this)); |
| } |
| return reinterpret_cast<int64_t>(monitor_); |
| } |
| |
| private: |
| friend class base::RefCountedThreadSafe<MonitorFinder>; |
| ~MonitorFinder() {} |
| |
| void FetchMonitorFromWidget() { |
| InterlockedExchange(&request_sent_, 0); |
| content::RenderFrameHost* rfh = |
| content::RenderFrameHost::FromID(process_id_, render_frame_id_); |
| if (!rfh) |
| return; |
| gfx::NativeView native_view = rfh->GetNativeView(); |
| #if defined(USE_AURA) |
| aura::WindowTreeHost* host = native_view->GetHost(); |
| if (!host) |
| return; |
| HWND window = host->GetAcceleratedWidget(); |
| #else |
| HWND window = native_view; |
| #endif |
| HMONITOR monitor = ::MonitorFromWindow(window, MONITOR_DEFAULTTONULL); |
| InterlockedExchangePointer(reinterpret_cast<void* volatile*>(&monitor_), |
| monitor); |
| } |
| |
| const int process_id_; |
| const int render_frame_id_; |
| volatile HMONITOR monitor_; |
| volatile long request_sent_; |
| }; |
| #elif !defined(OS_MACOSX) |
| // TODO(cpu): Support Linux someday. |
| class MonitorFinder : public base::RefCountedThreadSafe<MonitorFinder> { |
| public: |
| MonitorFinder(int, int) {} |
| int64_t GetMonitor() { return 0; } |
| |
| private: |
| friend class base::RefCountedThreadSafe<MonitorFinder>; |
| ~MonitorFinder() {} |
| }; |
| #endif |
| |
| PepperFlashDRMHost::PepperFlashDRMHost(BrowserPpapiHost* host, |
| PP_Instance instance, |
| PP_Resource resource) |
| : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), |
| weak_factory_(this) { |
| // Grant permissions to read the flash voucher file. |
| int render_process_id; |
| int render_frame_id; |
| bool success = host->GetRenderFrameIDsForInstance( |
| instance, &render_process_id, &render_frame_id); |
| base::FilePath plugin_dir = host->GetPluginPath().DirName(); |
| DCHECK(!plugin_dir.empty() && success); |
| base::FilePath voucher_file = plugin_dir.AppendASCII(kVoucherFilename); |
| content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( |
| render_process_id, voucher_file); |
| |
| fetcher_ = new DeviceIDFetcher(render_process_id); |
| monitor_finder_ = new MonitorFinder(render_process_id, render_frame_id); |
| monitor_finder_->GetMonitor(); |
| } |
| |
| PepperFlashDRMHost::~PepperFlashDRMHost() {} |
| |
| int32_t PepperFlashDRMHost::OnResourceMessageReceived( |
| const IPC::Message& msg, |
| ppapi::host::HostMessageContext* context) { |
| PPAPI_BEGIN_MESSAGE_MAP(PepperFlashDRMHost, msg) |
| PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetDeviceID, |
| OnHostMsgGetDeviceID) |
| PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetHmonitor, |
| OnHostMsgGetHmonitor) |
| PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_MonitorIsExternal, |
| OnHostMsgMonitorIsExternal) |
| PPAPI_END_MESSAGE_MAP() |
| return PP_ERROR_FAILED; |
| } |
| |
| int32_t PepperFlashDRMHost::OnHostMsgGetDeviceID( |
| ppapi::host::HostMessageContext* context) { |
| if (!fetcher_->Start(base::Bind(&PepperFlashDRMHost::GotDeviceID, |
| weak_factory_.GetWeakPtr(), |
| context->MakeReplyMessageContext()))) { |
| return PP_ERROR_INPROGRESS; |
| } |
| return PP_OK_COMPLETIONPENDING; |
| } |
| |
| int32_t PepperFlashDRMHost::OnHostMsgGetHmonitor( |
| ppapi::host::HostMessageContext* context) { |
| int64_t monitor_id = monitor_finder_->GetMonitor(); |
| if (monitor_id) { |
| context->reply_msg = PpapiPluginMsg_FlashDRM_GetHmonitorReply(monitor_id); |
| return PP_OK; |
| } |
| return PP_ERROR_FAILED; |
| } |
| |
| int32_t PepperFlashDRMHost::OnHostMsgMonitorIsExternal( |
| ppapi::host::HostMessageContext* context) { |
| int64_t monitor_id = monitor_finder_->GetMonitor(); |
| if (!monitor_id) |
| return PP_ERROR_FAILED; |
| |
| PP_Bool is_external = PP_FALSE; |
| #if defined(OS_MACOSX) |
| if (!MonitorFinder::IsMonitorBuiltIn(monitor_id)) |
| is_external = PP_TRUE; |
| #endif |
| context->reply_msg = |
| PpapiPluginMsg_FlashDRM_MonitorIsExternalReply(is_external); |
| return PP_OK; |
| } |
| |
| void PepperFlashDRMHost::GotDeviceID( |
| ppapi::host::ReplyMessageContext reply_context, |
| const std::string& id, |
| int32_t result) { |
| if (id.empty() && result == PP_OK) { |
| NOTREACHED(); |
| result = PP_ERROR_FAILED; |
| } |
| reply_context.params.set_result(result); |
| host()->SendReply(reply_context, |
| PpapiPluginMsg_FlashDRM_GetDeviceIDReply(id)); |
| } |
| |
| } // namespace chrome |