| // 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 { | |
| // A "safe" way to run callbacks, doing nothing if they are not | |
| // pending (active). | |
| void SafeRunCallback(scoped_refptr<TrackedCallback>* callback, int32_t error); | |
| 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_.GetRendererSender() | |
| : 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_ |