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