Home | History | Annotate | Download | only in pepper
      1 // Copyright 2013 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 "content/browser/renderer_host/pepper/pepper_renderer_connection.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/ref_counted.h"
      9 #include "content/browser/browser_child_process_host_impl.h"
     10 #include "content/browser/ppapi_plugin_process_host.h"
     11 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
     12 #include "content/common/pepper_renderer_instance_data.h"
     13 #include "content/common/view_messages.h"
     14 #include "content/browser/renderer_host/pepper/pepper_file_ref_host.h"
     15 #include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
     16 #include "content/public/browser/content_browser_client.h"
     17 #include "content/public/common/content_client.h"
     18 #include "ipc/ipc_message_macros.h"
     19 #include "ppapi/host/resource_host.h"
     20 #include "ppapi/proxy/ppapi_message_utils.h"
     21 #include "ppapi/proxy/ppapi_messages.h"
     22 #include "ppapi/proxy/resource_message_params.h"
     23 
     24 namespace content {
     25 
     26 namespace {
     27 
     28 const uint32 kFilteredMessageClasses[] = {PpapiMsgStart, ViewMsgStart, };
     29 
     30 // Responsible for creating the pending resource hosts, holding their IDs until
     31 // all of them have been created for a single message, and sending the reply to
     32 // say that the hosts have been created.
     33 class PendingHostCreator : public base::RefCounted<PendingHostCreator> {
     34  public:
     35   PendingHostCreator(BrowserPpapiHostImpl* host,
     36                      BrowserMessageFilter* connection,
     37                      int routing_id,
     38                      int sequence_id,
     39                      size_t nested_msgs_size);
     40 
     41   // Adds the given resource host as a pending one. The host is remembered as
     42   // host number |index|, and will ultimately be sent to the plugin to be
     43   // attached to a real resource.
     44   void AddPendingResourceHost(
     45       size_t index,
     46       scoped_ptr<ppapi::host::ResourceHost> resource_host);
     47 
     48  private:
     49   friend class base::RefCounted<PendingHostCreator>;
     50 
     51   // When the last reference to this class is released, all of the resource
     52   // hosts would have been added. This destructor sends the message to the
     53   // plugin to tell it to attach real hosts to all of the pending hosts that
     54   // have been added by this object.
     55   ~PendingHostCreator();
     56 
     57   BrowserPpapiHostImpl* host_;
     58   BrowserMessageFilter* connection_;
     59   int routing_id_;
     60   int sequence_id_;
     61   std::vector<int> pending_resource_host_ids_;
     62 };
     63 
     64 PendingHostCreator::PendingHostCreator(BrowserPpapiHostImpl* host,
     65                                        BrowserMessageFilter* connection,
     66                                        int routing_id,
     67                                        int sequence_id,
     68                                        size_t nested_msgs_size)
     69     : host_(host),
     70       connection_(connection),
     71       routing_id_(routing_id),
     72       sequence_id_(sequence_id),
     73       pending_resource_host_ids_(nested_msgs_size, 0) {}
     74 
     75 void PendingHostCreator::AddPendingResourceHost(
     76     size_t index,
     77     scoped_ptr<ppapi::host::ResourceHost> resource_host) {
     78   pending_resource_host_ids_[index] =
     79       host_->GetPpapiHost()->AddPendingResourceHost(resource_host.Pass());
     80 }
     81 
     82 PendingHostCreator::~PendingHostCreator() {
     83   connection_->Send(new PpapiHostMsg_CreateResourceHostsFromHostReply(
     84       routing_id_, sequence_id_, pending_resource_host_ids_));
     85 }
     86 
     87 }  // namespace
     88 
     89 PepperRendererConnection::PepperRendererConnection(int render_process_id)
     90     : BrowserMessageFilter(kFilteredMessageClasses,
     91                            arraysize(kFilteredMessageClasses)),
     92       render_process_id_(render_process_id) {
     93   // Only give the renderer permission for stable APIs.
     94   in_process_host_.reset(new BrowserPpapiHostImpl(this,
     95                                                   ppapi::PpapiPermissions(),
     96                                                   "",
     97                                                   base::FilePath(),
     98                                                   base::FilePath(),
     99                                                   true /* in_process */,
    100                                                   false /* external_plugin */));
    101 }
    102 
    103 PepperRendererConnection::~PepperRendererConnection() {}
    104 
    105 BrowserPpapiHostImpl* PepperRendererConnection::GetHostForChildProcess(
    106     int child_process_id) const {
    107   DCHECK_CURRENTLY_ON(BrowserThread::IO);
    108 
    109   // Find the plugin which this message refers to. Check NaCl plugins first.
    110   BrowserPpapiHostImpl* host = static_cast<BrowserPpapiHostImpl*>(
    111       GetContentClient()->browser()->GetExternalBrowserPpapiHost(
    112           child_process_id));
    113 
    114   if (!host) {
    115     // Check trusted pepper plugins.
    116     for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
    117       if (iter->process() &&
    118           iter->process()->GetData().id == child_process_id) {
    119         // Found the plugin.
    120         host = iter->host_impl();
    121         break;
    122       }
    123     }
    124   }
    125 
    126   // If the message is being sent from an in-process plugin, we own the
    127   // BrowserPpapiHost.
    128   if (!host && child_process_id == 0) {
    129     host = in_process_host_.get();
    130   }
    131 
    132   return host;
    133 }
    134 
    135 bool PepperRendererConnection::OnMessageReceived(const IPC::Message& msg) {
    136   if (in_process_host_->GetPpapiHost()->OnMessageReceived(msg))
    137     return true;
    138 
    139   bool handled = true;
    140   IPC_BEGIN_MESSAGE_MAP(PepperRendererConnection, msg)
    141     IPC_MESSAGE_HANDLER(PpapiHostMsg_CreateResourceHostsFromHost,
    142                         OnMsgCreateResourceHostsFromHost)
    143     IPC_MESSAGE_HANDLER(ViewHostMsg_DidCreateInProcessInstance,
    144                         OnMsgDidCreateInProcessInstance)
    145     IPC_MESSAGE_HANDLER(ViewHostMsg_DidDeleteInProcessInstance,
    146                         OnMsgDidDeleteInProcessInstance)
    147     IPC_MESSAGE_UNHANDLED(handled = false)
    148   IPC_END_MESSAGE_MAP()
    149 
    150   return handled;
    151 }
    152 
    153 void PepperRendererConnection::OnMsgCreateResourceHostsFromHost(
    154     int routing_id,
    155     int child_process_id,
    156     const ppapi::proxy::ResourceMessageCallParams& params,
    157     PP_Instance instance,
    158     const std::vector<IPC::Message>& nested_msgs) {
    159   BrowserPpapiHostImpl* host = GetHostForChildProcess(child_process_id);
    160   if (!host) {
    161     DLOG(ERROR) << "Invalid plugin process ID.";
    162     return;
    163   }
    164 
    165   scoped_refptr<PendingHostCreator> creator = new PendingHostCreator(
    166       host, this, routing_id, params.sequence(), nested_msgs.size());
    167   for (size_t i = 0; i < nested_msgs.size(); ++i) {
    168     const IPC::Message& nested_msg = nested_msgs[i];
    169     scoped_ptr<ppapi::host::ResourceHost> resource_host;
    170     if (host->IsValidInstance(instance)) {
    171       if (nested_msg.type() == PpapiHostMsg_FileRef_CreateForRawFS::ID) {
    172         // FileRef_CreateForRawFS is only permitted from the renderer. Because
    173         // of this, we handle this message here and not in
    174         // content_browser_pepper_host_factory.cc.
    175         base::FilePath external_path;
    176         if (ppapi::UnpackMessage<PpapiHostMsg_FileRef_CreateForRawFS>(
    177                 nested_msg, &external_path)) {
    178           resource_host.reset(new PepperFileRefHost(
    179               host, instance, params.pp_resource(), external_path));
    180         }
    181       } else if (nested_msg.type() ==
    182                  PpapiHostMsg_FileSystem_CreateFromRenderer::ID) {
    183         // Similarly, FileSystem_CreateFromRenderer is only permitted from the
    184         // renderer.
    185         std::string root_url;
    186         PP_FileSystemType file_system_type;
    187         if (ppapi::UnpackMessage<PpapiHostMsg_FileSystem_CreateFromRenderer>(
    188                 nested_msg, &root_url, &file_system_type)) {
    189           PepperFileSystemBrowserHost* browser_host =
    190               new PepperFileSystemBrowserHost(
    191                   host, instance, params.pp_resource(), file_system_type);
    192           resource_host.reset(browser_host);
    193           // Open the file system resource host. This is an asynchronous
    194           // operation, and we must only add the pending resource host and
    195           // send the message once it completes.
    196           browser_host->OpenExisting(
    197               GURL(root_url),
    198               base::Bind(&PendingHostCreator::AddPendingResourceHost,
    199                          creator,
    200                          i,
    201                          base::Passed(&resource_host)));
    202           // Do not fall through; the fall-through case adds the pending
    203           // resource host to the list. We must do this asynchronously.
    204           continue;
    205         }
    206       }
    207     }
    208 
    209     if (!resource_host.get()) {
    210       resource_host = host->GetPpapiHost()->CreateResourceHost(
    211           params, instance, nested_msg);
    212     }
    213 
    214     if (resource_host.get())
    215       creator->AddPendingResourceHost(i, resource_host.Pass());
    216   }
    217 
    218   // Note: All of the pending host IDs that were added as part of this
    219   // operation will automatically be sent to the plugin when |creator| is
    220   // released. This may happen immediately, or (if there are asynchronous
    221   // requests to create resource hosts), once all of them complete.
    222 }
    223 
    224 void PepperRendererConnection::OnMsgDidCreateInProcessInstance(
    225     PP_Instance instance,
    226     const PepperRendererInstanceData& instance_data) {
    227   PepperRendererInstanceData data = instance_data;
    228   data.render_process_id = render_process_id_;
    229   in_process_host_->AddInstance(instance, data);
    230 }
    231 
    232 void PepperRendererConnection::OnMsgDidDeleteInProcessInstance(
    233     PP_Instance instance) {
    234   in_process_host_->DeleteInstance(instance);
    235 }
    236 
    237 }  // namespace content
    238