// 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 #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 { 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(monitor_); } private: friend class base::RefCountedThreadSafe; ~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(&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 { public: MonitorFinder(int, int) {} int64_t GetMonitor() { return 0; } private: friend class base::RefCountedThreadSafe; ~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