| // 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 <stddef.h> | |
| #include <stdint.h> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| #include "base/macros.h" | |
| #include "base/memory/ref_counted.h" | |
| #include "ppapi/c/pp_instance.h" | |
| #include "ppapi/c/pp_var.h" | |
| #include "ppapi/proxy/ppapi_proxy_export.h" | |
| #include "ppapi/proxy/raw_var_data.h" | |
| #include "ppapi/proxy/serialized_handle.h" | |
| #include "ppapi/proxy/serialized_structs.h" | |
| #include "ppapi/proxy/var_serialization_rules.h" | |
| namespace base { | |
| 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<SerializedVar>. | |
| void WriteToMessage(base::Pickle* m) const { inner_->WriteToMessage(m); } | |
| // If ReadFromMessage has been called, WriteDataToMessage will write the var | |
| // that has been read from ReadFromMessage back to a message. This is used | |
| // when converting handles for use in NaCl. | |
| void WriteDataToMessage(base::Pickle* m, | |
| const HandleWriter& handle_writer) const { | |
| inner_->WriteDataToMessage(m, handle_writer); | |
| } | |
| bool ReadFromMessage(const base::Pickle* m, base::PickleIterator* iter) { | |
| return inner_->ReadFromMessage(m, iter); | |
| } | |
| bool is_valid_var() const { | |
| return inner_->is_valid_var(); | |
| } | |
| // Returns the shared memory handles associated with this SerializedVar. | |
| std::vector<SerializedHandle*> GetHandles() const { | |
| return inner_->GetHandles(); | |
| } | |
| 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<Inner> { | |
| public: | |
| Inner(); | |
| Inner(VarSerializationRules* serialization_rules); | |
| ~Inner(); | |
| VarSerializationRules* serialization_rules() { | |
| return serialization_rules_.get(); | |
| } | |
| void set_serialization_rules(VarSerializationRules* serialization_rules) { | |
| serialization_rules_ = serialization_rules; | |
| } | |
| bool is_valid_var() const { | |
| return is_valid_var_; | |
| } | |
| std::vector<SerializedHandle*> GetHandles() { | |
| return (raw_var_data_ ? raw_var_data_->GetHandles() : | |
| std::vector<SerializedHandle*>()); | |
| } | |
| // 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(base::Pickle* m) const; | |
| void WriteDataToMessage(base::Pickle* m, | |
| const HandleWriter& handle_writer) const; | |
| bool ReadFromMessage(const base::Pickle* m, base::PickleIterator* iter); | |
| // Sets the cleanup mode. See the CleanupMode enum below. | |
| void SetCleanupModeToEndSendPassRef(); | |
| void SetCleanupModeToEndReceiveCallerOwned(); | |
| 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 | |
| }; | |
| // 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<VarSerializationRules> 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_; | |
| // If the var is not properly serialized, this will be false. | |
| bool is_valid_var_; | |
| #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 | |
| // 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 some types of PP_Var | |
| // (e.g. PP_VARTYPE_STRING). The data is stored in |raw_var_data_| and the | |
| // PP_Var is constructed when |GetVar()| is called. | |
| std::unique_ptr<RawVarDataGraph> raw_var_data_; | |
| DISALLOW_COPY_AND_ASSIGN(Inner); | |
| }; | |
| SerializedVar(VarSerializationRules* serialization_rules); | |
| mutable scoped_refptr<Inner> 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<SerializedVar>* 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<SerializedVar>); | |
| // 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<SerializedVar>* OutParam(); | |
| private: | |
| Dispatcher* dispatcher_; | |
| uint32_t* output_count_; | |
| PP_Var** output_; | |
| std::vector<SerializedVar> 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); | |
| bool is_valid_var() { return serialized_.is_valid_var(); } | |
| 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<SerializedVar>& 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<SerializedVar>& serialized_; | |
| // Filled by Get(). | |
| std::vector<PP_Var> 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<SerializedVar>* serialized); | |
| ~SerializedVarVectorOutParam(); | |
| uint32_t* CountOutParam() { return &count_; } | |
| PP_Var** ArrayOutParam(Dispatcher* dispatcher); | |
| private: | |
| Dispatcher* dispatcher_; | |
| std::vector<SerializedVar>* 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); | |
| PP_Var GetVar() const { return inner_->GetVar(); } | |
| }; | |
| } // namespace proxy | |
| } // namespace ppapi | |
| #endif // PPAPI_PROXY_SERIALIZED_VAR_H_ |