Home | History | Annotate | Download | only in proxy
      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 "ppapi/proxy/plugin_resource.h"
      6 
      7 #include <limits>
      8 
      9 #include "ppapi/proxy/plugin_globals.h"
     10 #include "ppapi/proxy/ppapi_messages.h"
     11 #include "ppapi/shared_impl/ppapi_globals.h"
     12 
     13 namespace ppapi {
     14 namespace proxy {
     15 
     16 PluginResource::PluginResource(Connection connection, PP_Instance instance)
     17     : Resource(OBJECT_IS_PROXY, instance),
     18       connection_(connection),
     19       next_sequence_number_(1),
     20       sent_create_to_browser_(false),
     21       sent_create_to_renderer_(false),
     22       resource_reply_thread_registrar_(
     23           PpapiGlobals::Get()->IsPluginGlobals() ?
     24               PluginGlobals::Get()->resource_reply_thread_registrar() : NULL) {
     25 }
     26 
     27 PluginResource::~PluginResource() {
     28   if (sent_create_to_browser_) {
     29     connection_.browser_sender->Send(
     30         new PpapiHostMsg_ResourceDestroyed(pp_resource()));
     31   }
     32   if (sent_create_to_renderer_) {
     33     connection_.renderer_sender->Send(
     34         new PpapiHostMsg_ResourceDestroyed(pp_resource()));
     35   }
     36 
     37   if (resource_reply_thread_registrar_)
     38     resource_reply_thread_registrar_->Unregister(pp_resource());
     39 }
     40 
     41 void PluginResource::OnReplyReceived(
     42     const proxy::ResourceMessageReplyParams& params,
     43     const IPC::Message& msg) {
     44   TRACE_EVENT2("ppapi proxy", "PluginResource::OnReplyReceived",
     45                "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
     46                "Line", IPC_MESSAGE_ID_LINE(msg.type()));
     47   // Grab the callback for the reply sequence number and run it with |msg|.
     48   CallbackMap::iterator it = callbacks_.find(params.sequence());
     49   if (it == callbacks_.end()) {
     50     DCHECK(false) << "Callback does not exist for an expected sequence number.";
     51   } else {
     52     scoped_refptr<PluginResourceCallbackBase> callback = it->second;
     53     callbacks_.erase(it);
     54     callback->Run(params, msg);
     55   }
     56 }
     57 
     58 void PluginResource::NotifyLastPluginRefWasDeleted() {
     59   Resource::NotifyLastPluginRefWasDeleted();
     60 
     61   // The callbacks may hold referrences to this object. Normally, we will get
     62   // reply messages from the host side and remove them. However, it is possible
     63   // that some replies from the host never arrive, e.g., the corresponding
     64   // renderer crashes. In that case, we have to clean up the callbacks,
     65   // otherwise this object will live forever.
     66   callbacks_.clear();
     67 }
     68 
     69 void PluginResource::NotifyInstanceWasDeleted() {
     70   Resource::NotifyInstanceWasDeleted();
     71 
     72   // Please see comments in NotifyLastPluginRefWasDeleted() about why we must
     73   // clean up the callbacks.
     74   // It is possible that NotifyLastPluginRefWasDeleted() is never called for a
     75   // resource. For example, those singleton-style resources such as
     76   // GamepadResource never expose references to the plugin and thus won't
     77   // receive a NotifyLastPluginRefWasDeleted() call. For those resources, we
     78   // need to clean up callbacks when the instance goes away.
     79   callbacks_.clear();
     80 }
     81 
     82 void PluginResource::SendCreate(Destination dest, const IPC::Message& msg) {
     83   TRACE_EVENT2("ppapi proxy", "PluginResource::SendCreate",
     84                "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
     85                "Line", IPC_MESSAGE_ID_LINE(msg.type()));
     86   if (dest == RENDERER) {
     87     DCHECK(!sent_create_to_renderer_);
     88     sent_create_to_renderer_ = true;
     89   } else {
     90     DCHECK(!sent_create_to_browser_);
     91     sent_create_to_browser_ = true;
     92   }
     93   ResourceMessageCallParams params(pp_resource(), GetNextSequence());
     94   GetSender(dest)->Send(
     95       new PpapiHostMsg_ResourceCreated(params, pp_instance(), msg));
     96 }
     97 
     98 void PluginResource::AttachToPendingHost(Destination dest,
     99                                          int pending_host_id) {
    100   // Connecting to a pending host is a replacement for "create".
    101   if (dest == RENDERER) {
    102     DCHECK(!sent_create_to_renderer_);
    103     sent_create_to_renderer_ = true;
    104   } else {
    105     DCHECK(!sent_create_to_browser_);
    106     sent_create_to_browser_ = true;
    107   }
    108   GetSender(dest)->Send(
    109       new PpapiHostMsg_AttachToPendingHost(pp_resource(), pending_host_id));
    110 }
    111 
    112 void PluginResource::Post(Destination dest, const IPC::Message& msg) {
    113   TRACE_EVENT2("ppapi proxy", "PluginResource::Post",
    114                "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
    115                "Line", IPC_MESSAGE_ID_LINE(msg.type()));
    116   ResourceMessageCallParams params(pp_resource(), GetNextSequence());
    117   SendResourceCall(dest, params, msg);
    118 }
    119 
    120 bool PluginResource::SendResourceCall(
    121     Destination dest,
    122     const ResourceMessageCallParams& call_params,
    123     const IPC::Message& nested_msg) {
    124   // For in-process plugins, we need to send the routing ID with the request.
    125   // The browser then uses that routing ID when sending the reply so it will be
    126   // routed back to the correct RenderFrameImpl.
    127   if (dest == BROWSER && connection_.in_process) {
    128     return GetSender(dest)->Send(new PpapiHostMsg_InProcessResourceCall(
    129         connection_.browser_sender_routing_id,
    130         call_params,
    131         nested_msg));
    132   } else {
    133     return GetSender(dest)->Send(
    134         new PpapiHostMsg_ResourceCall(call_params, nested_msg));
    135   }
    136 }
    137 
    138 int32_t PluginResource::GenericSyncCall(
    139     Destination dest,
    140     const IPC::Message& msg,
    141     IPC::Message* reply,
    142     ResourceMessageReplyParams* reply_params) {
    143   TRACE_EVENT2("ppapi proxy", "PluginResource::GenericSyncCall",
    144                "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
    145                "Line", IPC_MESSAGE_ID_LINE(msg.type()));
    146   ResourceMessageCallParams params(pp_resource(), GetNextSequence());
    147   params.set_has_callback();
    148   bool success = GetSender(dest)->Send(new PpapiHostMsg_ResourceSyncCall(
    149       params, msg, reply_params, reply));
    150   if (success)
    151     return reply_params->result();
    152   return PP_ERROR_FAILED;
    153 }
    154 
    155 int32_t PluginResource::GetNextSequence() {
    156   // Return the value with wraparound, making sure we don't make a sequence
    157   // number with a 0 ID. Note that signed wraparound is undefined in C++ so we
    158   // manually check.
    159   int32_t ret = next_sequence_number_;
    160   if (next_sequence_number_ == std::numeric_limits<int32_t>::max())
    161     next_sequence_number_ = 1;  // Skip 0 which is invalid.
    162   else
    163     next_sequence_number_++;
    164   return ret;
    165 }
    166 
    167 }  // namespace proxy
    168 }  // namespace ppapi
    169