// 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 #include "base/basictypes.h" #include "base/compiler_specific.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); virtual ~PluginResource(); // 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|. virtual 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. virtual void NotifyLastPluginRefWasDeleted() override; virtual 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( // 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 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 int32_t Call(Destination dest, const IPC::Message& msg, const CallbackType& callback, scoped_refptr 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( // RENDERER, PpapiHostMsg_MyResourceType_MyRequestMessage(), // ¶m_1, ¶m_2); template int32_t SyncCall(Destination dest, const IPC::Message& msg); template int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a); template int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b); template int32_t SyncCall(Destination dest, const IPC::Message& msg, A* a, B* b, C* c); template int32_t SyncCall( Destination dest, const IPC::Message& msg, A* a, B* b, C* c, D* d); template 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 > CallbackMap; CallbackMap callbacks_; scoped_refptr resource_reply_thread_registrar_; DISALLOW_COPY_AND_ASSIGN(PluginResource); }; template int32_t PluginResource::Call(Destination dest, const IPC::Message& msg, const CallbackType& callback) { return Call(dest, msg, callback, NULL); } template int32_t PluginResource::Call( Destination dest, const IPC::Message& msg, const CallbackType& callback, scoped_refptr 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 plugin_callback( new PluginResourceCallback(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 int32_t PluginResource::SyncCall(Destination dest, const IPC::Message& msg) { IPC::Message reply; ResourceMessageReplyParams reply_params; return GenericSyncCall(dest, msg, &reply, &reply_params); } template 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(reply, a)) return result; return PP_ERROR_FAILED; } template 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(reply, a, b)) return result; return PP_ERROR_FAILED; } template 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(reply, a, b, c)) return result; return PP_ERROR_FAILED; } template 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(reply, a, b, c, d)) return result; return PP_ERROR_FAILED; } template 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(reply, a, b, c, d, e)) return result; return PP_ERROR_FAILED; } } // namespace proxy } // namespace ppapi #endif // PPAPI_PROXY_PLUGIN_RESOURCE_H_