diff options
Diffstat (limited to 'ppapi/proxy/serialized_var.h')
-rw-r--r-- | ppapi/proxy/serialized_var.h | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h new file mode 100644 index 0000000..4d4230d --- /dev/null +++ b/ppapi/proxy/serialized_var.h @@ -0,0 +1,451 @@ +// Copyright (c) 2010 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 <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/linked_ptr.h" +#include "ppapi/c/pp_var.h" + +namespace IPC { +class Message; +} + +namespace pp { +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 must all use the same type and it +// must include a var and a dispatcher (this is a SerializedVar). But there are +// many combinations of proper reference counting for sending and receiving +// different types and when different data is avaliable (like the Dispatcher is +// not available at IPC read time). So SerializedVar has to encapsulate all of +// these modes. +// +// This makes SerializedVar complicate and easy to mess up. To make it +// reasonable to use all functions are protected and there are a use-specific +// classes that 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 to 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 SerializedVar { + public: + 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 + }; + + SerializedVar(); + ~SerializedVar(); + + // Backend implementation for IPC::ParamTraits<SerializedVar>. + void WriteToMessage(IPC::Message* m) const { + inner_->WriteToMessage(m); + } + bool ReadFromMessage(const IPC::Message* m, void** iter) { + return inner_->ReadFromMessage(m, iter); + } + + protected: + friend class SerializedVarReceiveInput; + friend class SerializedVarReturnValue; + friend class SerializedVarOutParam; + friend class SerializedVarSendInput; + friend class SerializedVarVectorReceiveInput; + + SerializedVar(VarSerializationRules* serialization_rules); + SerializedVar(VarSerializationRules* serialization, const PP_Var& var); + + VarSerializationRules* serialization_rules() const { + return inner_->serialization_rules(); + } + void set_serialization_rules(VarSerializationRules* s) const { + inner_->set_serialization_rules(s); + } + + void set_cleanup_mode(CleanupMode cm) const { + inner_->set_cleanup_mode(cm); + } + + // Returns the completed var for this object. The serialization rules must + // have been set already, and any string conversions must already have + // happened. + PP_Var GetVar() const { + return inner_->GetVar(); + } + + // Returns the var which has not had a string serialization happen yet. This + // is used for actually converting a string PP_Var to the string literal. + PP_Var GetIncompleteVar() const { + return inner_->GetIncompleteVar(); + } + + void SetVar(const PP_Var& var) const { + inner_->SetVar(var); + } + + // When this serialized var is a string var, returns the associated string. + // with the value. This can be called if the var isn't a string, but will + // just return the empty string in this case. + const std::string& GetString() const { + return inner_->GetString(); + } + + // Returns a pointer to the inner string associated with this class. The + // derived classes will use this when converting a PP_Var to the string + // literal. This can be called if the var isn't a string, but the value + // should not be written to (this simplifies the callers who can always pass + // the result of this function call to the VarSerializationRules classes). + std::string* GetStringPtr() const { + return inner_->GetStringPtr(); + } + + private: + class Inner { + public: + Inner(); + Inner(VarSerializationRules* serialization_rules); + Inner(VarSerializationRules* serialization_rules, const PP_Var& var); + ~Inner(); + + VarSerializationRules* serialization_rules() { + return serialization_rules_; + } + void set_serialization_rules(VarSerializationRules* serialization_rules) { + serialization_rules_ = serialization_rules; + } + + void set_cleanup_mode(CleanupMode cm) { cleanup_mode_ = cm; } + + // See outer class's declarations above. + PP_Var GetVar() const; + PP_Var GetIncompleteVar() const; + void SetVar(PP_Var var); + const std::string& GetString() const; + std::string* GetStringPtr(); + + void WriteToMessage(IPC::Message* m) const; + bool ReadFromMessage(const IPC::Message* m, void** iter); + + private: + // 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. + VarSerializationRules* serialization_rules_; + + // If this is set to VARTYPE_STRING and the 'value.id' is 0, then the + // string_value_ contains 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_; + + // Holds the literal string value to/from IPC. This will be valid of the + // var_ is VARTYPE_STRING. + std::string string_value_; + + 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 + + DISALLOW_COPY_AND_ASSIGN(Inner); + }; + + mutable linked_ptr<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(param)); +// } +class 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(); +}; + +// 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()); +// } +class 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. + ReceiveSerializedVarReturnValue(); + + 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 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 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 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); + + private: + const SerializedVar& serialized_; + + // Since the SerializedVar is const, we can't set its dispatcher (which is + // OK since we don't need to). But since we need it for our own uses, we + // track it here. Will be NULL before Get() is called. + Dispatcher* dispatcher_; + PP_Var var_; +}; + +// 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 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 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); + + 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 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_; +}; + +// For returning an array of PP_Vars to the other side and transferring +// ownership. +// +class 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_; +}; + +} // namespace proxy +} // namespace pp + +#endif // PPAPI_PROXY_SERIALIZED_VAR_H_ + |