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 // ¶m_1, ¶m_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_.get()) { 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