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 #ifndef PPAPI_PROXY_PLUGIN_RESOURCE_H_
      6 #define PPAPI_PROXY_PLUGIN_RESOURCE_H_
      7 
      8 #include <map>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/compiler_specific.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "ipc/ipc_message.h"
     14 #include "ipc/ipc_sender.h"
     15 #include "ppapi/c/pp_errors.h"
     16 #include "ppapi/proxy/connection.h"
     17 #include "ppapi/proxy/plugin_resource_callback.h"
     18 #include "ppapi/proxy/ppapi_message_utils.h"
     19 #include "ppapi/proxy/ppapi_proxy_export.h"
     20 #include "ppapi/proxy/resource_message_params.h"
     21 #include "ppapi/proxy/resource_reply_thread_registrar.h"
     22 #include "ppapi/shared_impl/resource.h"
     23 #include "ppapi/shared_impl/tracked_callback.h"
     24 namespace ppapi {
     25 namespace proxy {
     26 
     27 class PluginDispatcher;
     28 
     29 class PPAPI_PROXY_EXPORT PluginResource : public Resource {
     30  public:
     31   enum Destination {
     32     RENDERER = 0,
     33     BROWSER = 1
     34   };
     35 
     36   PluginResource(Connection connection, PP_Instance instance);
     37   virtual ~PluginResource();
     38 
     39   // Returns true if we've previously sent a create message to the browser
     40   // or renderer. Generally resources will use these to tell if they should
     41   // lazily send create messages.
     42   bool sent_create_to_browser() const { return sent_create_to_browser_; }
     43   bool sent_create_to_renderer() const { return sent_create_to_renderer_; }
     44 
     45   // This handles a reply to a resource call. It works by looking up the
     46   // callback that was registered when CallBrowser/CallRenderer was called
     47   // and calling it with |params| and |msg|.
     48   virtual void OnReplyReceived(const proxy::ResourceMessageReplyParams& params,
     49                                const IPC::Message& msg) OVERRIDE;
     50 
     51   // Resource overrides.
     52   // Note: Subclasses shouldn't override these methods directly. Instead, they
     53   // should implement LastPluginRefWasDeleted() or InstanceWasDeleted() to get
     54   // notified.
     55   virtual void NotifyLastPluginRefWasDeleted() OVERRIDE;
     56   virtual void NotifyInstanceWasDeleted() OVERRIDE;
     57 
     58 
     59   // Sends a create message to the browser or renderer for the current resource.
     60   void SendCreate(Destination dest, const IPC::Message& msg);
     61 
     62   // When the host returnes a resource to the plugin, it will create a pending
     63   // ResourceHost and send an ID back to the plugin that identifies the pending
     64   // object. The plugin uses this function to connect the plugin resource with
     65   // the pending host resource. See also PpapiHostMsg_AttachToPendingHost. This
     66   // is in lieu of sending a create message.
     67   void AttachToPendingHost(Destination dest, int pending_host_id);
     68 
     69   // Sends the given IPC message as a resource request to the host
     70   // corresponding to this resource object and does not expect a reply.
     71   void Post(Destination dest, const IPC::Message& msg);
     72 
     73   // Like Post() but expects a response. |callback| is a |base::Callback| that
     74   // will be run when a reply message with a sequence number matching that of
     75   // the call is received. |ReplyMsgClass| is the type of the reply message that
     76   // is expected. An example of usage:
     77   //
     78   // Call<PpapiPluginMsg_MyResourceType_MyReplyMessage>(
     79   //     BROWSER,
     80   //     PpapiHostMsg_MyResourceType_MyRequestMessage(),
     81   //     base::Bind(&MyPluginResource::ReplyHandler, base::Unretained(this)));
     82   //
     83   // If a reply message to this call is received whose type does not match
     84   // |ReplyMsgClass| (for example, in the case of an error), the callback will
     85   // still be invoked but with the default values of the message parameters.
     86   //
     87   // Returns the new request's sequence number which can be used to identify
     88   // the callback. This value will never be 0, which you can use to identify
     89   // an invalid callback.
     90   //
     91   // Note: 1) When all plugin references to this resource are gone or the
     92   //          corresponding plugin instance is deleted, all pending callbacks
     93   //          are abandoned.
     94   //       2) It is *not* recommended to let |callback| hold any reference to
     95   //          |this|, in which it will be stored. Otherwise, this object will
     96   //          live forever if we fail to clean up the callback. It is safe to
     97   //          use base::Unretained(this) or a weak pointer, because this object
     98   //          will outlive the callback.
     99   template<typename ReplyMsgClass, typename CallbackType>
    100   int32_t Call(Destination dest,
    101                const IPC::Message& msg,
    102                const CallbackType& callback);
    103 
    104   // Comparing with the previous Call() method, this method takes
    105   // |reply_thread_hint| as a hint to determine which thread to handle the reply
    106   // message.
    107   //
    108   // If |reply_thread_hint| is non-blocking, the reply message will be handled
    109   // on the target thread of the callback; otherwise, it will be handled on the
    110   // main thread.
    111   //
    112   // If handling a reply message will cause a TrackedCallback to be run, it is
    113   // recommended to use this version of Call(). It eliminates unnecessary
    114   // thread switching and therefore has better performance.
    115   template<typename ReplyMsgClass, typename CallbackType>
    116   int32_t Call(Destination dest,
    117                const IPC::Message& msg,
    118                const CallbackType& callback,
    119                scoped_refptr<TrackedCallback> reply_thread_hint);
    120 
    121   // Calls the browser/renderer with sync messages. Returns the pepper error
    122   // code from the call.
    123   // |ReplyMsgClass| is the type of the reply message that is expected. If it
    124   // carries x parameters, then the method with x out parameters should be used.
    125   // An example of usage:
    126   //
    127   // // Assuming the reply message carries a string and an integer.
    128   // std::string param_1;
    129   // int param_2 = 0;
    130   // int32_t result = SyncCall<PpapiPluginMsg_MyResourceType_MyReplyMessage>(
    131   //     RENDERER, PpapiHostMsg_MyResourceType_MyRequestMessage(),
    132   //     &param_1, &param_2);
    133   template <class ReplyMsgClass>
    134   int32_t SyncCall(Destination dest, const IPC::Message& msg);
    135   template <class ReplyMsgClass, class A>
    136   int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a);
    137   template <class ReplyMsgClass, class A, class B>
    138   int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b);
    139   template <class ReplyMsgClass, class A, class B, class C>
    140   int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b, C* c);
    141   template <class ReplyMsgClass, class A, class B, class C, class D>
    142   int32_t SyncCall(
    143       Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d);
    144   template <class ReplyMsgClass, class A, class B, class C, class D, class E>
    145   int32_t SyncCall(
    146       Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e);
    147 
    148   int32_t GenericSyncCall(Destination dest,
    149                           const IPC::Message& msg,
    150                           IPC::Message* reply_msg,
    151                           ResourceMessageReplyParams* reply_params);
    152 
    153   const Connection& connection() { return connection_; }
    154 
    155  private:
    156   IPC::Sender* GetSender(Destination dest) {
    157     return dest == RENDERER ? connection_.renderer_sender :
    158                               connection_.browser_sender;
    159   }
    160 
    161   // Helper function to send a |PpapiHostMsg_ResourceCall| to the given
    162   // destination with |nested_msg| and |call_params|.
    163   bool SendResourceCall(Destination dest,
    164                         const ResourceMessageCallParams& call_params,
    165                         const IPC::Message& nested_msg);
    166 
    167   int32_t GetNextSequence();
    168 
    169   Connection connection_;
    170 
    171   // Use GetNextSequence to retrieve the next value.
    172   int32_t next_sequence_number_;
    173 
    174   bool sent_create_to_browser_;
    175   bool sent_create_to_renderer_;
    176 
    177   typedef std::map<int32_t, scoped_refptr<PluginResourceCallbackBase> >
    178       CallbackMap;
    179   CallbackMap callbacks_;
    180 
    181   scoped_refptr<ResourceReplyThreadRegistrar> resource_reply_thread_registrar_;
    182 
    183   DISALLOW_COPY_AND_ASSIGN(PluginResource);
    184 };
    185 
    186 template<typename ReplyMsgClass, typename CallbackType>
    187 int32_t PluginResource::Call(Destination dest,
    188                              const IPC::Message& msg,
    189                              const CallbackType& callback) {
    190   return Call<ReplyMsgClass>(dest, msg, callback, NULL);
    191 }
    192 
    193 template<typename ReplyMsgClass, typename CallbackType>
    194 int32_t PluginResource::Call(
    195     Destination dest,
    196     const IPC::Message& msg,
    197     const CallbackType& callback,
    198     scoped_refptr<TrackedCallback> reply_thread_hint) {
    199   TRACE_EVENT2("ppapi proxy", "PluginResource::Call",
    200                "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
    201                "Line", IPC_MESSAGE_ID_LINE(msg.type()));
    202   ResourceMessageCallParams params(pp_resource(), next_sequence_number_++);
    203   // Stash the |callback| in |callbacks_| identified by the sequence number of
    204   // the call.
    205   scoped_refptr<PluginResourceCallbackBase> plugin_callback(
    206       new PluginResourceCallback<ReplyMsgClass, CallbackType>(callback));
    207   callbacks_.insert(std::make_pair(params.sequence(), plugin_callback));
    208   params.set_has_callback();
    209 
    210   if (resource_reply_thread_registrar_) {
    211     resource_reply_thread_registrar_->Register(
    212         pp_resource(), params.sequence(), reply_thread_hint);
    213   }
    214   SendResourceCall(dest, params, msg);
    215   return params.sequence();
    216 }
    217 
    218 template <class ReplyMsgClass>
    219 int32_t PluginResource::SyncCall(Destination dest, const IPC::Message& msg) {
    220   IPC::Message reply;
    221   ResourceMessageReplyParams reply_params;
    222   return GenericSyncCall(dest, msg, &reply, &reply_params);
    223 }
    224 
    225 template <class ReplyMsgClass, class A>
    226 int32_t PluginResource::SyncCall(
    227     Destination dest, const IPC::Message& msg, A* a) {
    228   IPC::Message reply;
    229   ResourceMessageReplyParams reply_params;
    230   int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params);
    231 
    232   if (UnpackMessage<ReplyMsgClass>(reply, a))
    233     return result;
    234   return PP_ERROR_FAILED;
    235 }
    236 
    237 template <class ReplyMsgClass, class A, class B>
    238 int32_t PluginResource::SyncCall(
    239     Destination dest, const IPC::Message& msg, A* a, B* b) {
    240   IPC::Message reply;
    241   ResourceMessageReplyParams reply_params;
    242   int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params);
    243 
    244   if (UnpackMessage<ReplyMsgClass>(reply, a, b))
    245     return result;
    246   return PP_ERROR_FAILED;
    247 }
    248 
    249 template <class ReplyMsgClass, class A, class B, class C>
    250 int32_t PluginResource::SyncCall(
    251     Destination dest, const IPC::Message& msg, A* a, B* b, C* c) {
    252   IPC::Message reply;
    253   ResourceMessageReplyParams reply_params;
    254   int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params);
    255 
    256   if (UnpackMessage<ReplyMsgClass>(reply, a, b, c))
    257     return result;
    258   return PP_ERROR_FAILED;
    259 }
    260 
    261 template <class ReplyMsgClass, class A, class B, class C, class D>
    262 int32_t PluginResource::SyncCall(
    263     Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d) {
    264   IPC::Message reply;
    265   ResourceMessageReplyParams reply_params;
    266   int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params);
    267 
    268   if (UnpackMessage<ReplyMsgClass>(reply, a, b, c, d))
    269     return result;
    270   return PP_ERROR_FAILED;
    271 }
    272 
    273 template <class ReplyMsgClass, class A, class B, class C, class D, class E>
    274 int32_t PluginResource::SyncCall(
    275     Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e) {
    276   IPC::Message reply;
    277   ResourceMessageReplyParams reply_params;
    278   int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params);
    279 
    280   if (UnpackMessage<ReplyMsgClass>(reply, a, b, c, d, e))
    281     return result;
    282   return PP_ERROR_FAILED;
    283 }
    284 
    285 }  // namespace proxy
    286 }  // namespace ppapi
    287 
    288 #endif  // PPAPI_PROXY_PLUGIN_RESOURCE_H_
    289