• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
sent_create_to_browser()42   bool sent_create_to_browser() const { return sent_create_to_browser_; }
sent_create_to_renderer()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 
connection()153   const Connection& connection() { return connection_; }
154 
155  private:
GetSender(Destination dest)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>
Call(Destination dest,const IPC::Message & msg,const CallbackType & callback)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>
Call(Destination dest,const IPC::Message & msg,const CallbackType & callback,scoped_refptr<TrackedCallback> reply_thread_hint)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>
SyncCall(Destination dest,const IPC::Message & msg)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>
SyncCall(Destination dest,const IPC::Message & msg,A * 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>
SyncCall(Destination dest,const IPC::Message & msg,A * a,B * 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>
SyncCall(Destination dest,const IPC::Message & msg,A * a,B * b,C * 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>
SyncCall(Destination dest,const IPC::Message & msg,A * a,B * b,C * c,D * 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>
SyncCall(Destination dest,const IPC::Message & msg,A * a,B * b,C * c,D * d,E * 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