Home | History | Annotate | Download | only in pepper
      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 
     35 using content::BrowserPpapiHost;
     36 
     37 namespace chrome {
     38 
     39 namespace {
     40 const 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.
     49 class 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.
    102 class 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 
    113 PepperFlashDRMHost::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 
    134 PepperFlashDRMHost::~PepperFlashDRMHost() {}
    135 
    136 int32_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 
    150 int32_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 
    160 int32_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 
    170 int32_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 
    186 void 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