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