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