pepper_flash_drm_host.cc revision 23730a6e56a168d1879203e4b3819bb36e3d8f1f
1// Copyright (c) 2012 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_flash_drm_host.h" 6 7#if defined(OS_WIN) 8#include <Windows.h> 9#endif 10 11#include "base/bind.h" 12#include "base/compiler_specific.h" 13#include "base/logging.h" 14#include "base/memory/ref_counted.h" 15#include "content/public/browser/browser_ppapi_host.h" 16#include "content/public/browser/browser_thread.h" 17#include "content/public/browser/child_process_security_policy.h" 18#include "content/public/browser/render_frame_host.h" 19#include "content/public/common/pepper_plugin_info.h" 20#include "ppapi/c/pp_errors.h" 21#include "ppapi/host/dispatch_host_message.h" 22#include "ppapi/host/host_message_context.h" 23#include "ppapi/host/ppapi_host.h" 24#include "ppapi/proxy/ppapi_messages.h" 25 26#if defined(USE_AURA) 27#include "ui/aura/window.h" 28#include "ui/aura/window_tree_host.h" 29#endif 30 31#if defined(OS_MACOSX) 32#include "chrome/browser/renderer_host/pepper/monitor_finder_mac.h" 33#endif 34 35using content::BrowserPpapiHost; 36 37namespace chrome { 38 39namespace { 40const base::FilePath::CharType kVoucherFilename[] = 41 FILE_PATH_LITERAL("plugin.vch"); 42} 43 44#if defined (OS_WIN) 45// Helper class to get the UI thread which monitor is showing the 46// window associated with the instance's render view. Since we get 47// called by the IO thread and we cannot block, the first answer is 48// of GetMonitor() may be NULL, but eventually it will contain the 49// right monitor. 50class MonitorFinder : public base::RefCountedThreadSafe<MonitorFinder> { 51 public: 52 MonitorFinder(int process_id, int render_frame_id) 53 : process_id_(process_id), 54 render_frame_id_(render_frame_id), 55 monitor_(NULL), 56 request_sent_(0) { 57 } 58 59 int64_t GetMonitor() { 60 // We use |request_sent_| as an atomic boolean so that we 61 // never have more than one task posted at a given time. We 62 // do this because we don't know how often our client is going 63 // to call and we can't cache the |monitor_| value. 64 if (InterlockedCompareExchange(&request_sent_, 1, 0) == 0) { 65 content::BrowserThread::PostTask( 66 content::BrowserThread::UI, FROM_HERE, 67 base::Bind(&MonitorFinder::FetchMonitorFromWidget, this)); 68 } 69 return reinterpret_cast<int64_t>(monitor_); 70 } 71 72 private: 73 friend class base::RefCountedThreadSafe<MonitorFinder>; 74 ~MonitorFinder() { } 75 76 void FetchMonitorFromWidget() { 77 InterlockedExchange(&request_sent_, 0); 78 content::RenderFrameHost* rfh = 79 content::RenderFrameHost::FromID(process_id_, render_frame_id_); 80 if (!rfh) 81 return; 82 gfx::NativeView native_view = rfh->GetNativeView(); 83#if defined(USE_AURA) 84 aura::WindowTreeHost* host = native_view->GetHost(); 85 if (!host) 86 return; 87 HWND window = host->GetAcceleratedWidget(); 88#else 89 HWND window = native_view; 90#endif 91 HMONITOR monitor = ::MonitorFromWindow(window, MONITOR_DEFAULTTONULL); 92 InterlockedExchangePointer(reinterpret_cast<void* volatile *>(&monitor_), 93 monitor); 94 } 95 96 const int process_id_; 97 const int render_frame_id_; 98 volatile HMONITOR monitor_; 99 volatile long request_sent_; 100}; 101#elif !defined(OS_MACOSX) 102// TODO(cpu): Support Linux someday. 103class MonitorFinder : public base::RefCountedThreadSafe<MonitorFinder> { 104 public: 105 MonitorFinder(int, int) { } 106 int64_t GetMonitor() { return 0; } 107 108 private: 109 friend class base::RefCountedThreadSafe<MonitorFinder>; 110 ~MonitorFinder() { } 111}; 112#endif 113 114PepperFlashDRMHost::PepperFlashDRMHost(BrowserPpapiHost* host, 115 PP_Instance instance, 116 PP_Resource resource) 117 : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), 118 weak_factory_(this){ 119 // Grant permissions to read the flash voucher file. 120 int render_process_id; 121 int render_frame_id; 122 bool success = 123 host->GetRenderFrameIDsForInstance( 124 instance, &render_process_id, &render_frame_id); 125 base::FilePath plugin_dir = host->GetPluginPath().DirName(); 126 DCHECK(!plugin_dir.empty() && success); 127 base::FilePath voucher_file = plugin_dir.Append( 128 base::FilePath(kVoucherFilename)); 129 content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( 130 render_process_id, voucher_file); 131 132 fetcher_ = new DeviceIDFetcher(render_process_id); 133 monitor_finder_ = new MonitorFinder(render_process_id, render_frame_id); 134 monitor_finder_->GetMonitor(); 135} 136 137PepperFlashDRMHost::~PepperFlashDRMHost() { 138} 139 140int32_t PepperFlashDRMHost::OnResourceMessageReceived( 141 const IPC::Message& msg, 142 ppapi::host::HostMessageContext* context) { 143 IPC_BEGIN_MESSAGE_MAP(PepperFlashDRMHost, msg) 144 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetDeviceID, 145 OnHostMsgGetDeviceID) 146 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetHmonitor, 147 OnHostMsgGetHmonitor) 148 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_MonitorIsExternal, 149 OnHostMsgMonitorIsExternal) 150 IPC_END_MESSAGE_MAP() 151 return PP_ERROR_FAILED; 152} 153 154int32_t PepperFlashDRMHost::OnHostMsgGetDeviceID( 155 ppapi::host::HostMessageContext* context) { 156 if (!fetcher_->Start(base::Bind(&PepperFlashDRMHost::GotDeviceID, 157 weak_factory_.GetWeakPtr(), 158 context->MakeReplyMessageContext()))) { 159 return PP_ERROR_INPROGRESS; 160 } 161 return PP_OK_COMPLETIONPENDING; 162} 163 164int32_t PepperFlashDRMHost::OnHostMsgGetHmonitor( 165 ppapi::host::HostMessageContext* context) { 166 int64_t monitor_id = monitor_finder_->GetMonitor(); 167 if (monitor_id) { 168 context->reply_msg = PpapiPluginMsg_FlashDRM_GetHmonitorReply(monitor_id); 169 return PP_OK; 170 } else { 171 return PP_ERROR_FAILED; 172 } 173} 174 175int32_t PepperFlashDRMHost::OnHostMsgMonitorIsExternal( 176 ppapi::host::HostMessageContext* context) { 177 int64_t monitor_id = monitor_finder_->GetMonitor(); 178 if (monitor_id) { 179 // TODO(bbudge) get information about whether monitor is external. 180 context->reply_msg = 181 PpapiPluginMsg_FlashDRM_MonitorIsExternalReply(PP_FALSE); 182 return PP_OK; 183 } else { 184 return PP_ERROR_FAILED; 185 } 186} 187 188void PepperFlashDRMHost::GotDeviceID( 189 ppapi::host::ReplyMessageContext reply_context, 190 const std::string& id, 191 int32_t result) { 192 if (id.empty() && result == PP_OK) { 193 NOTREACHED(); 194 result = PP_ERROR_FAILED; 195 } 196 reply_context.params.set_result(result); 197 host()->SendReply(reply_context, 198 PpapiPluginMsg_FlashDRM_GetDeviceIDReply(id)); 199} 200 201} // namespace chrome 202