pepper_flash_drm_host.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
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_widget_host.h"
19#include "content/public/browser/render_widget_host_view.h"
20#include "content/public/common/pepper_plugin_info.h"
21#include "ppapi/c/pp_errors.h"
22#include "ppapi/host/dispatch_host_message.h"
23#include "ppapi/host/host_message_context.h"
24#include "ppapi/host/ppapi_host.h"
25#include "ppapi/proxy/ppapi_messages.h"
26
27#if defined(USE_AURA)
28#include "ui/aura/root_window.h"
29#endif
30
31using content::BrowserPpapiHost;
32
33namespace chrome {
34
35namespace {
36const base::FilePath::CharType kVoucherFilename[] =
37    FILE_PATH_LITERAL("plugin.vch");
38}
39
40#if defined (OS_WIN)
41// Helper class to get the UI thread which monitor is showing the
42// window associated with the instance's render view. Since we get
43// called by the IO thread and we cannot block, the first answer is
44// of GetMonitor() may be NULL, but eventually it will contain the
45// right monitor.
46class MonitorFinder : public base::RefCountedThreadSafe<MonitorFinder> {
47 public:
48  MonitorFinder(int process_id, int render_id)
49      : process_id_(process_id),
50        render_id_(render_id),
51        monitor_(NULL),
52        request_sent_(0) {
53  }
54
55  int64_t GetMonitor() {
56    // We use |request_sent_| as an atomic boolean so that we
57    // never have more than one task posted at a given time. We
58    // do this because we don't know how often our client is going
59    // to call and we can't cache the |monitor_| value.
60    if (InterlockedCompareExchange(&request_sent_, 1, 0) == 0) {
61      content::BrowserThread::PostTask(
62          content::BrowserThread::UI, FROM_HERE,
63          base::Bind(&MonitorFinder::FetchMonitorFromWidget, this));
64    }
65    return reinterpret_cast<int64_t>(monitor_);
66  }
67
68 private:
69  friend class base::RefCountedThreadSafe<MonitorFinder>;
70  ~MonitorFinder() { }
71
72  void FetchMonitorFromWidget() {
73    InterlockedExchange(&request_sent_, 0);
74    content::RenderWidgetHost* rwh =
75        content::RenderWidgetHost::FromID(process_id_, render_id_);
76    if (!rwh)
77      return;
78    content::RenderWidgetHostView* view = rwh->GetView();
79    if (!view)
80      return;
81    gfx::NativeView native_view = view->GetNativeView();
82#if defined(USE_AURA)
83    aura::RootWindow* root = native_view->GetRootWindow();
84    if (!root)
85      return;
86    HWND window = root->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_id_;
97  volatile HMONITOR monitor_;
98  volatile long request_sent_;
99};
100#else
101// TODO(cpu): Support Mac and 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_view_id;
121  bool success =
122      host->GetRenderViewIDsForInstance(
123          instance, &render_process_id, &render_view_id);
124  base::FilePath plugin_dir = host->GetPluginPath().DirName();
125  DCHECK(!plugin_dir.empty() && success);
126  base::FilePath voucher_file = plugin_dir.Append(
127      base::FilePath(kVoucherFilename));
128  content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
129      render_process_id, voucher_file);
130
131  fetcher_ = new DeviceIDFetcher(render_process_id);
132  monitor_finder_ = new MonitorFinder(render_process_id, render_view_id);
133  monitor_finder_->GetMonitor();
134}
135
136PepperFlashDRMHost::~PepperFlashDRMHost() {
137}
138
139int32_t PepperFlashDRMHost::OnResourceMessageReceived(
140    const IPC::Message& msg,
141    ppapi::host::HostMessageContext* context) {
142  IPC_BEGIN_MESSAGE_MAP(PepperFlashDRMHost, msg)
143    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetDeviceID,
144                                        OnHostMsgGetDeviceID)
145    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetHmonitor,
146                                        OnHostMsgGetHmonitor)
147  IPC_END_MESSAGE_MAP()
148  return PP_ERROR_FAILED;
149}
150
151int32_t PepperFlashDRMHost::OnHostMsgGetDeviceID(
152    ppapi::host::HostMessageContext* context) {
153  if (!fetcher_->Start(base::Bind(&PepperFlashDRMHost::GotDeviceID,
154                                  weak_factory_.GetWeakPtr(),
155                                  context->MakeReplyMessageContext()))) {
156    return PP_ERROR_INPROGRESS;
157  }
158  return PP_OK_COMPLETIONPENDING;
159}
160
161int32_t PepperFlashDRMHost::OnHostMsgGetHmonitor(
162    ppapi::host::HostMessageContext* context) {
163  int64_t monitor_id = monitor_finder_->GetMonitor();
164  if (monitor_id) {
165    context->reply_msg = PpapiPluginMsg_FlashDRM_GetHmonitorReply(monitor_id);
166    return PP_OK;
167  } else {
168    return PP_ERROR_FAILED;
169  }
170}
171
172void PepperFlashDRMHost::GotDeviceID(
173    ppapi::host::ReplyMessageContext reply_context,
174    const std::string& id) {
175  reply_context.params.set_result(
176      id.empty() ? PP_ERROR_FAILED : PP_OK);
177  host()->SendReply(reply_context,
178                    PpapiPluginMsg_FlashDRM_GetDeviceIDReply(id));
179}
180
181}  // namespace chrome
182