// 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_SERIALIZED_VAR_H_ #define PPAPI_PROXY_SERIALIZED_VAR_H_ #include #include #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/shared_memory.h" #include "ppapi/c/pp_instance.h" #include "ppapi/c/pp_var.h" #include "ppapi/proxy/ppapi_proxy_export.h" #include "ppapi/proxy/serialized_handle.h" #include "ppapi/proxy/serialized_structs.h" #include "ppapi/proxy/var_serialization_rules.h" class PickleIterator; namespace IPC { class Message; } namespace ppapi { namespace proxy { class Dispatcher; class VarSerializationRules; // This class encapsulates a var so that we can serialize and deserialize it. // The problem is that for strings, serialization and deserialization requires // knowledge from outside about how to get at or create a string. So this // object groups the var with a dispatcher so that string values can be set or // gotten. // // Declare IPC messages as using this type, but don't use it directly (it has // no useful public methods). Instead, instantiate one of the helper classes // below which are conveniently named for each use case to prevent screwups. // // Design background // ----------------- // This is sadly super complicated. The IPC system needs a consistent type to // use for sending and receiving vars (this is a SerializedVar). But there are // different combinations of reference counting for sending and receiving // objects and for dealing with strings // // This makes SerializedVar complicated and easy to mess up. To make it // reasonable to use, all functions are protected and there are use-specific // classes that each encapsulate exactly one type of use in a way that typically // won't compile if you do the wrong thing. // // The IPC system is designed to pass things around and will make copies in // some cases, so our system must be designed so that this stuff will work. // This is challenging when the SerializedVar must do some cleanup after the // message is sent. To work around this, we create an inner class using a // linked_ptr so all copies of a SerializedVar can share and we can guarantee // that the actual data will get cleaned up on shutdown. // // Constness // --------- // SerializedVar basically doesn't support const. Everything is mutable and // most functions are declared const. This unfortunateness is because of the // way the IPC system works. When deserializing, it will have a const // SerializedVar in a Tuple and this will be given to the function. We kind of // want to modify that to convert strings and do refcounting. // // The helper classes used for accessing the SerializedVar have more reasonable // behavior and will enforce that you don't do stupid things. class PPAPI_PROXY_EXPORT SerializedVar { public: SerializedVar(); ~SerializedVar(); // Backend implementation for IPC::ParamTraits. void WriteToMessage(IPC::Message* m) const { inner_->WriteToMessage(m); } bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter) { return inner_->ReadFromMessage(m, iter); } // Used by chrome/nacl/nacl_ipc_adapter.cc SerializedHandle* GetPluginShmemHandle() const { return inner_->GetPluginShmemHandle(); } void WriteRawVarHeader(IPC::Message* m) const { inner_->WriteRawVarHeader(m); } protected: friend class SerializedVarReceiveInput; friend class SerializedVarReturnValue; friend class SerializedVarOutParam; friend class SerializedVarSendInput; friend class SerializedVarSendInputShmem; friend class SerializedVarTestConstructor; friend class SerializedVarVectorReceiveInput; class PPAPI_PROXY_EXPORT Inner : public base::RefCounted { public: Inner(); Inner(VarSerializationRules* serialization_rules); ~Inner(); VarSerializationRules* serialization_rules() { return serialization_rules_; } void set_serialization_rules(VarSerializationRules* serialization_rules) { serialization_rules_ = serialization_rules; } // See outer class's declarations above. PP_Var GetVar(); void SetVar(PP_Var var); void SetInstance(PP_Instance instance); // For the SerializedVarTestConstructor, this writes the Var value as if // it was just received off the wire, without any serialization rules. void ForceSetVarValueForTest(PP_Var value); void WriteToMessage(IPC::Message* m) const; bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter); // Sets the cleanup mode. See the CleanupMode enum below. void SetCleanupModeToEndSendPassRef(); void SetCleanupModeToEndReceiveCallerOwned(); // Returns a handle in the underlying data, if it exists. SerializedHandle* GetPluginShmemHandle() const; // Writes raw var data, excluding handles. void WriteRawVarHeader(IPC::Message* m) const; private: enum CleanupMode { // The serialized var won't do anything special in the destructor // (default). CLEANUP_NONE, // The serialized var will call EndSendPassRef in the destructor. END_SEND_PASS_REF, // The serialized var will call EndReceiveCallerOwned in the destructor. END_RECEIVE_CALLER_OWNED }; // Enum for array buffer message types. enum ShmemType { ARRAY_BUFFER_NO_SHMEM, ARRAY_BUFFER_SHMEM_HOST, ARRAY_BUFFER_SHMEM_PLUGIN, }; // ReadFromMessage() may be called on the I/O thread, e.g., when reading the // reply to a sync message. We cannot use the var tracker on the I/O thread, // which means we cannot create PP_Var for PP_VARTYPE_STRING and // PP_VARTYPE_ARRAY_BUFFER in ReadFromMessage(). So we save the raw var data // and create PP_Var later when GetVar() is called, which should happen on // the main thread. struct RawVarData { PP_VarType type; ShmemType shmem_type; std::string data; uint32 shmem_size; int host_handle_id; SerializedHandle plugin_handle; }; // Converts |raw_var_data_| to |var_|. It is a no-op if |raw_var_data_| is // NULL. void ConvertRawVarData(); // Rules for serializing and deserializing vars for this process type. // This may be NULL, but must be set before trying to serialize to IPC when // sending, or before converting back to a PP_Var when receiving. scoped_refptr serialization_rules_; // If this is set to VARTYPE_STRING and the 'value.id' is 0, then the // string_from_ipc_ holds the string. This means that the caller hasn't // called Deserialize with a valid Dispatcher yet, which is how we can // convert the serialized string value to a PP_Var string ID. // // This var may not be complete until the serialization rules are set when // reading from IPC since we'll need that to convert the string_value to // a string ID. Before this, the as_id will be 0 for VARTYPE_STRING. PP_Var var_; PP_Instance instance_; CleanupMode cleanup_mode_; #ifndef NDEBUG // When being sent or received over IPC, we should only be serialized or // deserialized once. These flags help us assert this is true. mutable bool has_been_serialized_; mutable bool has_been_deserialized_; #endif // It will be non-NULL if there is PP_VARTYPE_STRING or // PP_VARTYPE_ARRAY_BUFFER data from ReadFromMessage() that hasn't been // converted to PP_Var. scoped_ptr raw_var_data_; DISALLOW_COPY_AND_ASSIGN(Inner); }; SerializedVar(VarSerializationRules* serialization_rules); mutable scoped_refptr inner_; }; // Helpers for message sending side -------------------------------------------- // For sending a value to the remote side. // // Example for API: // void MyFunction(PP_Var) // IPC message: // IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar); // Sender would be: // void MyFunctionProxy(PP_Var param) { // Send(new MyFunctionMsg(SerializedVarSendInput(dispatcher, param)); // } class PPAPI_PROXY_EXPORT SerializedVarSendInput : public SerializedVar { public: SerializedVarSendInput(Dispatcher* dispatcher, const PP_Var& var); // Helper function for serializing a vector of input vars for serialization. static void ConvertVector(Dispatcher* dispatcher, const PP_Var* input, size_t input_count, std::vector* output); private: // Disallow the empty constructor, but keep the default copy constructor // which is required to send the object to the IPC system. SerializedVarSendInput(); }; // Specialization for optionally sending over shared memory. class PPAPI_PROXY_EXPORT SerializedVarSendInputShmem : public SerializedVar { public: SerializedVarSendInputShmem(Dispatcher* dispatcher, const PP_Var& var, const PP_Instance& instance); private: // Disallow the empty constructor, but keep the default copy constructor // which is required to send the object to the IPC system. SerializedVarSendInputShmem(); }; // For the calling side of a function returning a var. The sending side uses // SerializedVarReturnValue. // // Example for API: // PP_Var MyFunction() // IPC message: // IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); // Message handler would be: // PP_Var MyFunctionProxy() { // ReceiveSerializedVarReturnValue result; // Send(new MyFunctionMsg(&result)); // return result.Return(dispatcher()); // } // // TODO(yzshen): Move the dispatcher parameter to the constructor and store a // VarSerializationRules reference instead, in case the dispatcher is destroyed // while waiting for reply to the sync message. class PPAPI_PROXY_EXPORT ReceiveSerializedVarReturnValue : public SerializedVar { public: // Note that we can't set the dispatcher in the constructor because the // data will be overridden when the return value is set. This constructor is // normally used in the pattern above (operator= will be implicitly invoked // when the sync message writes the output values). ReceiveSerializedVarReturnValue(); // This constructor can be used when deserializing manually. This is useful // when you're getting strings "returned" via a struct and need to manually // get the PP_Vars out. In this case just do: // ReceiveSerializedVarReturnValue(serialized).Return(dispatcher); explicit ReceiveSerializedVarReturnValue(const SerializedVar& serialized); PP_Var Return(Dispatcher* dispatcher); private: DISALLOW_COPY_AND_ASSIGN(ReceiveSerializedVarReturnValue); }; // Example for API: // "void MyFunction(PP_Var* exception);" // IPC message: // IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); // Message handler would be: // void OnMsgMyFunction(PP_Var* exception) { // ReceiveSerializedException se(dispatcher(), exception) // Send(new PpapiHostMsg_Foo(&se)); // } class PPAPI_PROXY_EXPORT ReceiveSerializedException : public SerializedVar { public: ReceiveSerializedException(Dispatcher* dispatcher, PP_Var* exception); ~ReceiveSerializedException(); // Returns true if the exception passed in the constructor is set. Check // this before actually issuing the IPC. bool IsThrown() const; private: // The input/output exception we're wrapping. May be NULL. PP_Var* exception_; DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedException); }; // Helper class for when we're returning a vector of Vars. When it goes out // of scope it will automatically convert the vector filled by the IPC layer // into the array specified by the constructor params. // // Example for API: // "void MyFunction(uint32_t* count, PP_Var** vars);" // IPC message: // IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, std::vector); // Proxy function: // void MyFunction(uint32_t* count, PP_Var** vars) { // ReceiveSerializedVarVectorOutParam vect(dispatcher, count, vars); // Send(new MyMsg(vect.OutParam())); // } class PPAPI_PROXY_EXPORT ReceiveSerializedVarVectorOutParam { public: ReceiveSerializedVarVectorOutParam(Dispatcher* dispatcher, uint32_t* output_count, PP_Var** output); ~ReceiveSerializedVarVectorOutParam(); std::vector* OutParam(); private: Dispatcher* dispatcher_; uint32_t* output_count_; PP_Var** output_; std::vector vector_; DISALLOW_IMPLICIT_CONSTRUCTORS(ReceiveSerializedVarVectorOutParam); }; // Helpers for message receiving side ------------------------------------------ // For receiving a value from the remote side. // // Example for API: // void MyFunction(PP_Var) // IPC message: // IPC_MESSAGE_ROUTED1(MyFunction, SerializedVar); // Message handler would be: // void OnMsgMyFunction(SerializedVarReceiveInput param) { // MyFunction(param.Get()); // } class PPAPI_PROXY_EXPORT SerializedVarReceiveInput { public: // We rely on the implicit constructor here since the IPC layer will call // us with a SerializedVar. Pass this object by value, the copy constructor // will pass along the pointer (as cheap as passing a pointer arg). SerializedVarReceiveInput(const SerializedVar& serialized); ~SerializedVarReceiveInput(); PP_Var Get(Dispatcher* dispatcher); PP_Var GetForInstance(Dispatcher* dispatcher, PP_Instance instance); private: const SerializedVar& serialized_; }; // For receiving an input vector of vars from the remote side. // // Example: // OnMsgMyFunction(SerializedVarVectorReceiveInput vector) { // uint32_t size; // PP_Var* array = vector.Get(dispatcher, &size); // MyFunction(size, array); // } class PPAPI_PROXY_EXPORT SerializedVarVectorReceiveInput { public: SerializedVarVectorReceiveInput(const std::vector& serialized); ~SerializedVarVectorReceiveInput(); // Only call Get() once. It will return a pointer to the converted array and // place the array size in the out param. Will return NULL when the array is // empty. PP_Var* Get(Dispatcher* dispatcher, uint32_t* array_size); private: const std::vector& serialized_; // Filled by Get(). std::vector deserialized_; }; // For the receiving side of a function returning a var. The calling side uses // ReceiveSerializedVarReturnValue. // // Example for API: // PP_Var MyFunction() // IPC message: // IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); // Message handler would be: // void OnMsgMyFunction(SerializedVarReturnValue result) { // result.Return(dispatcher(), MyFunction()); // } class PPAPI_PROXY_EXPORT SerializedVarReturnValue { public: // We rely on the implicit constructor here since the IPC layer will call // us with a SerializedVar*. Pass this object by value, the copy constructor // will pass along the pointer (as cheap as passing a pointer arg). SerializedVarReturnValue(SerializedVar* serialized); void Return(Dispatcher* dispatcher, const PP_Var& var); // Helper function for code that doesn't use the pattern above, but gets // a return value from the remote side via a struct. You can pass in the // SerializedVar and a PP_Var will be created with return value semantics. static SerializedVar Convert(Dispatcher* dispatcher, const PP_Var& var); private: SerializedVar* serialized_; }; // For writing an out param to the remote side. // // Example for API: // "void MyFunction(PP_Var* out);" // IPC message: // IPC_SYNC_MESSAGE_ROUTED0_1(MyFunction, SerializedVar); // Message handler would be: // void OnMsgMyFunction(SerializedVarOutParam out_param) { // MyFunction(out_param.OutParam(dispatcher())); // } class PPAPI_PROXY_EXPORT SerializedVarOutParam { public: // We rely on the implicit constructor here since the IPC layer will call // us with a SerializedVar*. Pass this object by value, the copy constructor // will pass along the pointer (as cheap as passing a pointer arg). SerializedVarOutParam(SerializedVar* serialized); ~SerializedVarOutParam(); // Call this function only once. The caller should write its result to the // returned var pointer before this class goes out of scope. The var's // initial value will be VARTYPE_UNDEFINED. PP_Var* OutParam(Dispatcher* dispatcher); private: SerializedVar* serialized_; // This is the value actually written by the code and returned by OutParam. // We'll write this into serialized_ in our destructor. PP_Var writable_var_; Dispatcher* dispatcher_; }; // For returning an array of PP_Vars to the other side and transferring // ownership. // class PPAPI_PROXY_EXPORT SerializedVarVectorOutParam { public: SerializedVarVectorOutParam(std::vector* serialized); ~SerializedVarVectorOutParam(); uint32_t* CountOutParam() { return &count_; } PP_Var** ArrayOutParam(Dispatcher* dispatcher); private: Dispatcher* dispatcher_; std::vector* serialized_; uint32_t count_; PP_Var* array_; }; // For tests that just want to construct a SerializedVar for giving it to one // of the other classes. This emulates a SerializedVar just received over the // wire from another process. class PPAPI_PROXY_EXPORT SerializedVarTestConstructor : public SerializedVar { public: // For POD-types and objects. explicit SerializedVarTestConstructor(const PP_Var& pod_var); // For strings. explicit SerializedVarTestConstructor(const std::string& str); }; // For tests that want to read what's in a SerializedVar. class PPAPI_PROXY_EXPORT SerializedVarTestReader : public SerializedVar { public: explicit SerializedVarTestReader(const SerializedVar& var); // The "incomplete" var is the one sent over the wire. Strings and object // IDs have not yet been converted, so this is the thing that tests will // actually want to check. PP_Var GetVar() const { return inner_->GetVar(); } }; } // namespace proxy } // namespace ppapi #endif // PPAPI_PROXY_SERIALIZED_VAR_H_