|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef PPAPI_PROXY_PLUGIN_RESOURCE_H_ | 
|  | #define PPAPI_PROXY_PLUGIN_RESOURCE_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <map> | 
|  |  | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "ipc/ipc_message.h" | 
|  | #include "ipc/ipc_sender.h" | 
|  | #include "ppapi/c/pp_errors.h" | 
|  | #include "ppapi/proxy/connection.h" | 
|  | #include "ppapi/proxy/plugin_resource_callback.h" | 
|  | #include "ppapi/proxy/ppapi_message_utils.h" | 
|  | #include "ppapi/proxy/ppapi_proxy_export.h" | 
|  | #include "ppapi/proxy/resource_message_params.h" | 
|  | #include "ppapi/proxy/resource_reply_thread_registrar.h" | 
|  | #include "ppapi/shared_impl/resource.h" | 
|  | #include "ppapi/shared_impl/tracked_callback.h" | 
|  | namespace ppapi { | 
|  | namespace proxy { | 
|  |  | 
|  | class PluginDispatcher; | 
|  |  | 
|  | class PPAPI_PROXY_EXPORT PluginResource : public Resource { | 
|  | public: | 
|  | enum Destination { | 
|  | RENDERER = 0, | 
|  | BROWSER = 1 | 
|  | }; | 
|  |  | 
|  | PluginResource(Connection connection, PP_Instance instance); | 
|  | ~PluginResource() override; | 
|  |  | 
|  | // Returns true if we've previously sent a create message to the browser | 
|  | // or renderer. Generally resources will use these to tell if they should | 
|  | // lazily send create messages. | 
|  | bool sent_create_to_browser() const { return sent_create_to_browser_; } | 
|  | bool sent_create_to_renderer() const { return sent_create_to_renderer_; } | 
|  |  | 
|  | // This handles a reply to a resource call. It works by looking up the | 
|  | // callback that was registered when CallBrowser/CallRenderer was called | 
|  | // and calling it with |params| and |msg|. | 
|  | void OnReplyReceived(const proxy::ResourceMessageReplyParams& params, | 
|  | const IPC::Message& msg) override; | 
|  |  | 
|  | // Resource overrides. | 
|  | // Note: Subclasses shouldn't override these methods directly. Instead, they | 
|  | // should implement LastPluginRefWasDeleted() or InstanceWasDeleted() to get | 
|  | // notified. | 
|  | void NotifyLastPluginRefWasDeleted() override; | 
|  | void NotifyInstanceWasDeleted() override; | 
|  |  | 
|  | // Sends a create message to the browser or renderer for the current resource. | 
|  | void SendCreate(Destination dest, const IPC::Message& msg); | 
|  |  | 
|  | // When the host returnes a resource to the plugin, it will create a pending | 
|  | // ResourceHost and send an ID back to the plugin that identifies the pending | 
|  | // object. The plugin uses this function to connect the plugin resource with | 
|  | // the pending host resource. See also PpapiHostMsg_AttachToPendingHost. This | 
|  | // is in lieu of sending a create message. | 
|  | void AttachToPendingHost(Destination dest, int pending_host_id); | 
|  |  | 
|  | // Sends the given IPC message as a resource request to the host | 
|  | // corresponding to this resource object and does not expect a reply. | 
|  | void Post(Destination dest, const IPC::Message& msg); | 
|  |  | 
|  | // Like Post() but expects a response. |callback| is a |base::Callback| that | 
|  | // will be run when a reply message with a sequence number matching that of | 
|  | // the call is received. |ReplyMsgClass| is the type of the reply message that | 
|  | // is expected. An example of usage: | 
|  | // | 
|  | // Call<PpapiPluginMsg_MyResourceType_MyReplyMessage>( | 
|  | //     BROWSER, | 
|  | //     PpapiHostMsg_MyResourceType_MyRequestMessage(), | 
|  | //     base::Bind(&MyPluginResource::ReplyHandler, base::Unretained(this))); | 
|  | // | 
|  | // If a reply message to this call is received whose type does not match | 
|  | // |ReplyMsgClass| (for example, in the case of an error), the callback will | 
|  | // still be invoked but with the default values of the message parameters. | 
|  | // | 
|  | // Returns the new request's sequence number which can be used to identify | 
|  | // the callback. This value will never be 0, which you can use to identify | 
|  | // an invalid callback. | 
|  | // | 
|  | // Note: 1) When all plugin references to this resource are gone or the | 
|  | //          corresponding plugin instance is deleted, all pending callbacks | 
|  | //          are abandoned. | 
|  | //       2) It is *not* recommended to let |callback| hold any reference to | 
|  | //          |this|, in which it will be stored. Otherwise, this object will | 
|  | //          live forever if we fail to clean up the callback. It is safe to | 
|  | //          use base::Unretained(this) or a weak pointer, because this object | 
|  | //          will outlive the callback. | 
|  | template<typename ReplyMsgClass, typename CallbackType> | 
|  | int32_t Call(Destination dest, | 
|  | const IPC::Message& msg, | 
|  | const CallbackType& callback); | 
|  |  | 
|  | // Comparing with the previous Call() method, this method takes | 
|  | // |reply_thread_hint| as a hint to determine which thread to handle the reply | 
|  | // message. | 
|  | // | 
|  | // If |reply_thread_hint| is non-blocking, the reply message will be handled | 
|  | // on the target thread of the callback; otherwise, it will be handled on the | 
|  | // main thread. | 
|  | // | 
|  | // If handling a reply message will cause a TrackedCallback to be run, it is | 
|  | // recommended to use this version of Call(). It eliminates unnecessary | 
|  | // thread switching and therefore has better performance. | 
|  | template<typename ReplyMsgClass, typename CallbackType> | 
|  | int32_t Call(Destination dest, | 
|  | const IPC::Message& msg, | 
|  | const CallbackType& callback, | 
|  | scoped_refptr<TrackedCallback> reply_thread_hint); | 
|  |  | 
|  | // Calls the browser/renderer with sync messages. Returns the pepper error | 
|  | // code from the call. | 
|  | // |ReplyMsgClass| is the type of the reply message that is expected. If it | 
|  | // carries x parameters, then the method with x out parameters should be used. | 
|  | // An example of usage: | 
|  | // | 
|  | // // Assuming the reply message carries a string and an integer. | 
|  | // std::string param_1; | 
|  | // int param_2 = 0; | 
|  | // int32_t result = SyncCall<PpapiPluginMsg_MyResourceType_MyReplyMessage>( | 
|  | //     RENDERER, PpapiHostMsg_MyResourceType_MyRequestMessage(), | 
|  | //     ¶m_1, ¶m_2); | 
|  | template <class ReplyMsgClass> | 
|  | int32_t SyncCall(Destination dest, const IPC::Message& msg); | 
|  | template <class ReplyMsgClass, class A> | 
|  | int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a); | 
|  | template <class ReplyMsgClass, class A, class B> | 
|  | int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b); | 
|  | template <class ReplyMsgClass, class A, class B, class C> | 
|  | int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b, C* c); | 
|  | template <class ReplyMsgClass, class A, class B, class C, class D> | 
|  | int32_t SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d); | 
|  | template <class ReplyMsgClass, class A, class B, class C, class D, class E> | 
|  | int32_t SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e); | 
|  |  | 
|  | int32_t GenericSyncCall(Destination dest, | 
|  | const IPC::Message& msg, | 
|  | IPC::Message* reply_msg, | 
|  | ResourceMessageReplyParams* reply_params); | 
|  |  | 
|  | const Connection& connection() { return connection_; } | 
|  |  | 
|  | private: | 
|  | IPC::Sender* GetSender(Destination dest) { | 
|  | return dest == RENDERER ? connection_.renderer_sender : | 
|  | connection_.browser_sender; | 
|  | } | 
|  |  | 
|  | // Helper function to send a |PpapiHostMsg_ResourceCall| to the given | 
|  | // destination with |nested_msg| and |call_params|. | 
|  | bool SendResourceCall(Destination dest, | 
|  | const ResourceMessageCallParams& call_params, | 
|  | const IPC::Message& nested_msg); | 
|  |  | 
|  | int32_t GetNextSequence(); | 
|  |  | 
|  | Connection connection_; | 
|  |  | 
|  | // Use GetNextSequence to retrieve the next value. | 
|  | int32_t next_sequence_number_; | 
|  |  | 
|  | bool sent_create_to_browser_; | 
|  | bool sent_create_to_renderer_; | 
|  |  | 
|  | typedef std::map<int32_t, scoped_refptr<PluginResourceCallbackBase> > | 
|  | CallbackMap; | 
|  | CallbackMap callbacks_; | 
|  |  | 
|  | scoped_refptr<ResourceReplyThreadRegistrar> resource_reply_thread_registrar_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PluginResource); | 
|  | }; | 
|  |  | 
|  | template<typename ReplyMsgClass, typename CallbackType> | 
|  | int32_t PluginResource::Call(Destination dest, | 
|  | const IPC::Message& msg, | 
|  | const CallbackType& callback) { | 
|  | return Call<ReplyMsgClass>(dest, msg, callback, NULL); | 
|  | } | 
|  |  | 
|  | template<typename ReplyMsgClass, typename CallbackType> | 
|  | int32_t PluginResource::Call( | 
|  | Destination dest, | 
|  | const IPC::Message& msg, | 
|  | const CallbackType& callback, | 
|  | scoped_refptr<TrackedCallback> reply_thread_hint) { | 
|  | TRACE_EVENT2("ppapi proxy", "PluginResource::Call", | 
|  | "Class", IPC_MESSAGE_ID_CLASS(msg.type()), | 
|  | "Line", IPC_MESSAGE_ID_LINE(msg.type())); | 
|  | ResourceMessageCallParams params(pp_resource(), next_sequence_number_++); | 
|  | // Stash the |callback| in |callbacks_| identified by the sequence number of | 
|  | // the call. | 
|  | scoped_refptr<PluginResourceCallbackBase> plugin_callback( | 
|  | new PluginResourceCallback<ReplyMsgClass, CallbackType>(callback)); | 
|  | callbacks_.insert(std::make_pair(params.sequence(), plugin_callback)); | 
|  | params.set_has_callback(); | 
|  |  | 
|  | if (resource_reply_thread_registrar_.get()) { | 
|  | resource_reply_thread_registrar_->Register( | 
|  | pp_resource(), params.sequence(), reply_thread_hint); | 
|  | } | 
|  | SendResourceCall(dest, params, msg); | 
|  | return params.sequence(); | 
|  | } | 
|  |  | 
|  | template <class ReplyMsgClass> | 
|  | int32_t PluginResource::SyncCall(Destination dest, const IPC::Message& msg) { | 
|  | IPC::Message reply; | 
|  | ResourceMessageReplyParams reply_params; | 
|  | return GenericSyncCall(dest, msg, &reply, &reply_params); | 
|  | } | 
|  |  | 
|  | template <class ReplyMsgClass, class A> | 
|  | int32_t PluginResource::SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a) { | 
|  | IPC::Message reply; | 
|  | ResourceMessageReplyParams reply_params; | 
|  | int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); | 
|  |  | 
|  | if (UnpackMessage<ReplyMsgClass>(reply, a)) | 
|  | return result; | 
|  | return PP_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | template <class ReplyMsgClass, class A, class B> | 
|  | int32_t PluginResource::SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a, B* b) { | 
|  | IPC::Message reply; | 
|  | ResourceMessageReplyParams reply_params; | 
|  | int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); | 
|  |  | 
|  | if (UnpackMessage<ReplyMsgClass>(reply, a, b)) | 
|  | return result; | 
|  | return PP_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | template <class ReplyMsgClass, class A, class B, class C> | 
|  | int32_t PluginResource::SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a, B* b, C* c) { | 
|  | IPC::Message reply; | 
|  | ResourceMessageReplyParams reply_params; | 
|  | int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); | 
|  |  | 
|  | if (UnpackMessage<ReplyMsgClass>(reply, a, b, c)) | 
|  | return result; | 
|  | return PP_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | template <class ReplyMsgClass, class A, class B, class C, class D> | 
|  | int32_t PluginResource::SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d) { | 
|  | IPC::Message reply; | 
|  | ResourceMessageReplyParams reply_params; | 
|  | int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); | 
|  |  | 
|  | if (UnpackMessage<ReplyMsgClass>(reply, a, b, c, d)) | 
|  | return result; | 
|  | return PP_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | template <class ReplyMsgClass, class A, class B, class C, class D, class E> | 
|  | int32_t PluginResource::SyncCall( | 
|  | Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d, E* e) { | 
|  | IPC::Message reply; | 
|  | ResourceMessageReplyParams reply_params; | 
|  | int32_t result = GenericSyncCall(dest, msg, &reply, &reply_params); | 
|  |  | 
|  | if (UnpackMessage<ReplyMsgClass>(reply, a, b, c, d, e)) | 
|  | return result; | 
|  | return PP_ERROR_FAILED; | 
|  | } | 
|  |  | 
|  | }  // namespace proxy | 
|  | }  // namespace ppapi | 
|  |  | 
|  | #endif  // PPAPI_PROXY_PLUGIN_RESOURCE_H_ |