diff options
Diffstat (limited to 'ppapi/proxy/serialized_var.cc')
-rw-r--r-- | ppapi/proxy/serialized_var.cc | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc new file mode 100644 index 0000000..a76f219 --- /dev/null +++ b/ppapi/proxy/serialized_var.cc @@ -0,0 +1,457 @@ +// 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. + +#include "ppapi/proxy/serialized_var.h" + +#include "base/logging.h" +#include "ipc/ipc_message_utils.h" +#include "ppapi/proxy/dispatcher.h" +#include "ppapi/proxy/ppapi_param_traits.h" +#include "ppapi/proxy/var_serialization_rules.h" + +namespace pp { +namespace proxy { + +// SerializedVar::Inner -------------------------------------------------------- + +SerializedVar::Inner::Inner() + : serialization_rules_(NULL), + var_(PP_MakeUndefined()), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules) + : serialization_rules_(serialization_rules), + var_(PP_MakeUndefined()), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules, + const PP_Var& var) + : serialization_rules_(serialization_rules), + var_(var), + cleanup_mode_(CLEANUP_NONE) { +#ifndef NDEBUG + has_been_serialized_ = false; + has_been_deserialized_ = false; +#endif +} + +SerializedVar::Inner::~Inner() { + switch (cleanup_mode_) { + case END_SEND_PASS_REF: + serialization_rules_->EndSendPassRef(var_); + break; + case END_RECEIVE_CALLER_OWNED: + serialization_rules_->EndReceiveCallerOwned(var_); + break; + default: + break; + } +} + +PP_Var SerializedVar::Inner::GetVar() const { + DCHECK(serialization_rules_); + + // If we're a string var, we should have already converted the string value + // to a var ID. + DCHECK(var_.type != PP_VARTYPE_STRING || var_.value.as_id != 0); + return var_; +} + +PP_Var SerializedVar::Inner::GetIncompleteVar() const { + DCHECK(serialization_rules_); + return var_; +} + +void SerializedVar::Inner::SetVar(PP_Var var) { + // Sanity check, when updating the var we should have received a + // serialization rules pointer already. + DCHECK(serialization_rules_); + var_ = var; +} + +const std::string& SerializedVar::Inner::GetString() const { + DCHECK(serialization_rules_); + return string_value_; +} + +std::string* SerializedVar::Inner::GetStringPtr() { + DCHECK(serialization_rules_); + return &string_value_; +} + +void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { + // When writing to the IPC messages, a serization rules handler should + // always have been set. + // + // When sending a message, it should be difficult to trigger this if you're + // using the SerializedVarSendInput class and giving a non-NULL dispatcher. + // Make sure you're using the proper "Send" helper class. + // + // It should be more common to see this when handling an incoming message + // that returns a var. This means the message handler didn't write to the + // output parameter, or possibly you used the wrong helper class + // (normally SerializedVarReturnValue). + DCHECK(serialization_rules_); + +#ifndef NDEBUG + // We should only be serializing something once. + DCHECK(!has_been_serialized_); + has_been_serialized_ = true; +#endif + + // If the var is not a string type, we should not have ended up with any + // string data. + DCHECK(var_.type == PP_VARTYPE_STRING || string_value_.empty()); + + m->WriteInt(static_cast<int>(var_.type)); + switch (var_.type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + // These don't need any data associated with them other than the type we + // just serialized. + break; + case PP_VARTYPE_BOOL: + m->WriteBool(var_.value.as_bool); + break; + case PP_VARTYPE_INT32: + m->WriteInt(var_.value.as_int); + break; + case PP_VARTYPE_DOUBLE: + IPC::ParamTraits<double>::Write(m, var_.value.as_double); + break; + case PP_VARTYPE_STRING: + // TODO(brettw) in the case of an invalid string ID, it would be nice + // to send something to the other side such that a 0 ID would be + // generated there. Then the function implementing the interface can + // handle the invalid string as if it was in process rather than seeing + // what looks like a valid empty string. + m->WriteString(string_value_); + break; + case PP_VARTYPE_OBJECT: + m->WriteInt64(var_.value.as_id); + break; + } +} + +bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, void** iter) { +#ifndef NDEBUG + // We should only deserialize something once or will end up with leaked + // references. + // + // One place this has happened in the past is using + // std::vector<SerializedVar>.resize(). If you're doing this manually instead + // of using the helper classes for handling in/out vectors of vars, be + // sure you use the same pattern as the SerializedVarVector classes. + DCHECK(!has_been_deserialized_); + has_been_deserialized_ = true; +#endif + + // When reading, the dispatcher should be set when we get a Deserialize + // call (which will supply a dispatcher). + int type; + if (!m->ReadInt(iter, &type)) + return false; + + bool success = false; + switch (type) { + case PP_VARTYPE_UNDEFINED: + case PP_VARTYPE_NULL: + // These don't have any data associated with them other than the type we + // just serialized. + success = true; + break; + case PP_VARTYPE_BOOL: + success = m->ReadBool(iter, &var_.value.as_bool); + break; + case PP_VARTYPE_INT32: + success = m->ReadInt(iter, &var_.value.as_int); + break; + case PP_VARTYPE_DOUBLE: + success = IPC::ParamTraits<double>::Read(m, iter, &var_.value.as_double); + break; + case PP_VARTYPE_STRING: + success = m->ReadString(iter, &string_value_); + var_.value.as_id = 0; + break; + case PP_VARTYPE_OBJECT: + success = m->ReadInt64(iter, &var_.value.as_id); + break; + default: + // Leave success as false. + break; + } + + // All success cases get here. We avoid writing the type above so that the + // output param is untouched (defaults to VARTYPE_UNDEFINED) even in the + // failure case. + if (success) + var_.type = static_cast<PP_VarType>(type); + return success; +} + +// SerializedVar --------------------------------------------------------------- + +SerializedVar::SerializedVar() : inner_(new Inner) { +} + +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules) + : inner_(new Inner(serialization_rules)) { +} + +SerializedVar::SerializedVar(VarSerializationRules* serialization_rules, + const PP_Var& var) + : inner_(new Inner(serialization_rules, var)) { +} + +SerializedVar::~SerializedVar() { +} + +// SerializedVarSendInput ------------------------------------------------------ + +SerializedVarSendInput::SerializedVarSendInput(Dispatcher* dispatcher, + const PP_Var& var) + : SerializedVar(dispatcher->serialization_rules(), var) { + dispatcher->serialization_rules()->SendCallerOwned(var, GetStringPtr()); +} + +// static +void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, + const PP_Var* input, + size_t input_count, + std::vector<SerializedVar>* output) { + output->resize(input_count); + for (size_t i = 0; i < input_count; i++) { + (*output)[i] = SerializedVar(dispatcher->serialization_rules(), input[i]); + dispatcher->serialization_rules()->SendCallerOwned(input[i], + (*output)[i].GetStringPtr()); + } +} + +// ReceiveSerializedVarReturnValue --------------------------------------------- + +ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { +} + +PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) { + set_serialization_rules(dispatcher->serialization_rules()); + SetVar(serialization_rules()->ReceivePassRef(GetIncompleteVar(), + GetString())); + return GetVar(); +} + +// ReceiveSerializedException -------------------------------------------------- + +ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher, + PP_Var* exception) + : SerializedVar(dispatcher->serialization_rules()), + exception_(exception) { +} + +ReceiveSerializedException::~ReceiveSerializedException() { + if (exception_) { + // When an output exception is specified, it will take ownership of the + // reference. + SetVar(serialization_rules()->ReceivePassRef(GetIncompleteVar(), + GetString())); + *exception_ = GetVar(); + } else { + // When no output exception is specified, the browser thinks we have a ref + // to an object that we don't want (this will happen only in the plugin + // since the browser will always specify an out exception for the plugin to + // write into). + // + // Strings don't need this handling since we can just avoid creating a + // Var from the std::string in the first place. + if (GetVar().type == PP_VARTYPE_OBJECT) + serialization_rules()->ReleaseObjectRef(GetVar()); + } +} + +bool ReceiveSerializedException::IsThrown() const { + return exception_ && exception_->type != PP_VARTYPE_UNDEFINED; +} + +// ReceiveSerializedVarVectorOutParam ------------------------------------------ + +ReceiveSerializedVarVectorOutParam::ReceiveSerializedVarVectorOutParam( + Dispatcher* dispatcher, + uint32_t* output_count, + PP_Var** output) + : dispatcher_(dispatcher), + output_count_(output_count), + output_(output) { +} + +ReceiveSerializedVarVectorOutParam::~ReceiveSerializedVarVectorOutParam() { + *output_count_ = static_cast<uint32_t>(vector_.size()); + if (!vector_.size()) { + *output_ = NULL; + return; + } + + *output_ = static_cast<PP_Var*>(malloc(vector_.size() * sizeof(PP_Var))); + for (size_t i = 0; i < vector_.size(); i++) { + // Here we just mimic what happens when returning a value. + ReceiveSerializedVarReturnValue converted; + SerializedVar* serialized = &converted; + *serialized = vector_[i]; + (*output_)[i] = converted.Return(dispatcher_); + } +} + +std::vector<SerializedVar>* ReceiveSerializedVarVectorOutParam::OutParam() { + return &vector_; +} + +// SerializedVarReceiveInput --------------------------------------------------- + +SerializedVarReceiveInput::SerializedVarReceiveInput( + const SerializedVar& serialized) + : serialized_(serialized), + dispatcher_(NULL), + var_(PP_MakeUndefined()) { +} + +SerializedVarReceiveInput::~SerializedVarReceiveInput() { +} + +PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) { + serialized_.set_serialization_rules(dispatcher->serialization_rules()); + + // Ensure that when the serialized var goes out of scope it cleans up the + // stuff we're making in BeginReceiveCallerOwned. + serialized_.set_cleanup_mode(SerializedVar::END_RECEIVE_CALLER_OWNED); + + serialized_.SetVar( + serialized_.serialization_rules()->BeginReceiveCallerOwned( + serialized_.GetIncompleteVar(), serialized_.GetStringPtr())); + return serialized_.GetVar(); +} + +// SerializedVarVectorReceiveInput --------------------------------------------- + +SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( + const std::vector<SerializedVar>& serialized) + : serialized_(serialized) { +} + +SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() { + for (size_t i = 0; i < deserialized_.size(); i++) { + serialized_[i].serialization_rules()->EndReceiveCallerOwned( + deserialized_[i]); + } +} + +PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher, + uint32_t* array_size) { + deserialized_.resize(serialized_.size()); + for (size_t i = 0; i < serialized_.size(); i++) { + // The vector must be able to clean themselves up after this call is + // torn down. + serialized_[i].set_serialization_rules(dispatcher->serialization_rules()); + + serialized_[i].SetVar( + serialized_[i].serialization_rules()->BeginReceiveCallerOwned( + serialized_[i].GetIncompleteVar(), serialized_[i].GetStringPtr())); + deserialized_[i] = serialized_[i].GetVar(); + } + + *array_size = static_cast<uint32_t>(serialized_.size()); + return deserialized_.size() > 0 ? &deserialized_[0] : NULL; +} + +// SerializedVarReturnValue ---------------------------------------------------- + +SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized) + : serialized_(serialized) { +} + +void SerializedVarReturnValue::Return(Dispatcher* dispatcher, + const PP_Var& var) { + serialized_->set_serialization_rules(dispatcher->serialization_rules()); + serialized_->SetVar(var); + + // Var must clean up after our BeginSendPassRef call. + serialized_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF); + + dispatcher->serialization_rules()->BeginSendPassRef( + serialized_->GetIncompleteVar(), serialized_->GetStringPtr()); +} + +// SerializedVarOutParam ------------------------------------------------------- + +SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized) + : serialized_(serialized), + writable_var_(PP_MakeUndefined()) { +} + +SerializedVarOutParam::~SerializedVarOutParam() { + if (serialized_->serialization_rules()) { + // When unset, OutParam wasn't called. We'll just leave the var untouched + // in that case. + serialized_->SetVar(writable_var_); + serialized_->serialization_rules()->BeginSendPassRef( + writable_var_, serialized_->GetStringPtr()); + + // Normally the current object will be created on the stack to wrap a + // SerializedVar and won't have a scope around the actual IPC send. So we + // need to tell the SerializedVar to do the begin/end send pass ref calls. + serialized_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF); + } +} + +PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) { + serialized_->set_serialization_rules(dispatcher->serialization_rules()); + return &writable_var_; +} + +// SerializedVarVectorOutParam ------------------------------------------------- + +SerializedVarVectorOutParam::SerializedVarVectorOutParam( + std::vector<SerializedVar>* serialized) + : dispatcher_(NULL), + serialized_(serialized), + count_(0), + array_(NULL) { +} + +SerializedVarVectorOutParam::~SerializedVarVectorOutParam() { + DCHECK(dispatcher_); + + // Convert the array written by the pepper code to the serialized structure. + // Note we can't use resize here, we have to allocate a new SerializedVar + // for each serialized item. See ParamTraits<vector<SerializedVar>>::Read. + serialized_->reserve(count_); + for (uint32_t i = 0; i < count_; i++) { + // Just mimic what we do for regular OutParams. + SerializedVar var; + SerializedVarOutParam out(&var); + *out.OutParam(dispatcher_) = array_[i]; + serialized_->push_back(var); + } + + // When returning arrays, the pepper code expects the caller to take + // ownership of the array. + free(array_); +} + +PP_Var** SerializedVarVectorOutParam::ArrayOutParam(Dispatcher* dispatcher) { + DCHECK(!dispatcher_); // Should only be called once. + dispatcher_ = dispatcher; + return &array_; +} + +} // namespace proxy +} // namespace pp + |