OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ppapi/proxy/serialized_var.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "ipc/ipc_message_utils.h" |
| 9 #include "ppapi/proxy/dispatcher.h" |
| 10 #include "ppapi/proxy/ppapi_param_traits.h" |
| 11 #include "ppapi/proxy/var_serialization_rules.h" |
| 12 |
| 13 namespace pp { |
| 14 namespace proxy { |
| 15 |
| 16 // SerializedVar::Inner -------------------------------------------------------- |
| 17 |
| 18 SerializedVar::Inner::Inner() |
| 19 : serialization_rules_(NULL), |
| 20 var_(PP_MakeUndefined()), |
| 21 cleanup_mode_(CLEANUP_NONE) { |
| 22 #ifndef NDEBUG |
| 23 has_been_serialized_ = false; |
| 24 has_been_deserialized_ = false; |
| 25 #endif |
| 26 } |
| 27 |
| 28 SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules) |
| 29 : serialization_rules_(serialization_rules), |
| 30 var_(PP_MakeUndefined()), |
| 31 cleanup_mode_(CLEANUP_NONE) { |
| 32 #ifndef NDEBUG |
| 33 has_been_serialized_ = false; |
| 34 has_been_deserialized_ = false; |
| 35 #endif |
| 36 } |
| 37 |
| 38 SerializedVar::Inner::Inner(VarSerializationRules* serialization_rules, |
| 39 const PP_Var& var) |
| 40 : serialization_rules_(serialization_rules), |
| 41 var_(var), |
| 42 cleanup_mode_(CLEANUP_NONE) { |
| 43 #ifndef NDEBUG |
| 44 has_been_serialized_ = false; |
| 45 has_been_deserialized_ = false; |
| 46 #endif |
| 47 } |
| 48 |
| 49 SerializedVar::Inner::~Inner() { |
| 50 switch (cleanup_mode_) { |
| 51 case END_SEND_PASS_REF: |
| 52 serialization_rules_->EndSendPassRef(var_); |
| 53 break; |
| 54 case END_RECEIVE_CALLER_OWNED: |
| 55 serialization_rules_->EndReceiveCallerOwned(var_); |
| 56 break; |
| 57 default: |
| 58 break; |
| 59 } |
| 60 } |
| 61 |
| 62 PP_Var SerializedVar::Inner::GetVar() const { |
| 63 DCHECK(serialization_rules_); |
| 64 |
| 65 // If we're a string var, we should have already converted the string value |
| 66 // to a var ID. |
| 67 DCHECK(var_.type != PP_VARTYPE_STRING || var_.value.as_id != 0); |
| 68 return var_; |
| 69 } |
| 70 |
| 71 PP_Var SerializedVar::Inner::GetIncompleteVar() const { |
| 72 DCHECK(serialization_rules_); |
| 73 return var_; |
| 74 } |
| 75 |
| 76 void SerializedVar::Inner::SetVar(PP_Var var) { |
| 77 // Sanity check, when updating the var we should have received a |
| 78 // serialization rules pointer already. |
| 79 DCHECK(serialization_rules_); |
| 80 var_ = var; |
| 81 } |
| 82 |
| 83 const std::string& SerializedVar::Inner::GetString() const { |
| 84 DCHECK(serialization_rules_); |
| 85 return string_value_; |
| 86 } |
| 87 |
| 88 std::string* SerializedVar::Inner::GetStringPtr() { |
| 89 DCHECK(serialization_rules_); |
| 90 return &string_value_; |
| 91 } |
| 92 |
| 93 void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { |
| 94 // When writing to the IPC messages, a serization rules handler should |
| 95 // always have been set. |
| 96 // |
| 97 // When sending a message, it should be difficult to trigger this if you're |
| 98 // using the SerializedVarSendInput class and giving a non-NULL dispatcher. |
| 99 // Make sure you're using the proper "Send" helper class. |
| 100 // |
| 101 // It should be more common to see this when handling an incoming message |
| 102 // that returns a var. This means the message handler didn't write to the |
| 103 // output parameter, or possibly you used the wrong helper class |
| 104 // (normally SerializedVarReturnValue). |
| 105 DCHECK(serialization_rules_); |
| 106 |
| 107 #ifndef NDEBUG |
| 108 // We should only be serializing something once. |
| 109 DCHECK(!has_been_serialized_); |
| 110 has_been_serialized_ = true; |
| 111 #endif |
| 112 |
| 113 // If the var is not a string type, we should not have ended up with any |
| 114 // string data. |
| 115 DCHECK(var_.type == PP_VARTYPE_STRING || string_value_.empty()); |
| 116 |
| 117 m->WriteInt(static_cast<int>(var_.type)); |
| 118 switch (var_.type) { |
| 119 case PP_VARTYPE_UNDEFINED: |
| 120 case PP_VARTYPE_NULL: |
| 121 // These don't need any data associated with them other than the type we |
| 122 // just serialized. |
| 123 break; |
| 124 case PP_VARTYPE_BOOL: |
| 125 m->WriteBool(var_.value.as_bool); |
| 126 break; |
| 127 case PP_VARTYPE_INT32: |
| 128 m->WriteInt(var_.value.as_int); |
| 129 break; |
| 130 case PP_VARTYPE_DOUBLE: |
| 131 IPC::ParamTraits<double>::Write(m, var_.value.as_double); |
| 132 break; |
| 133 case PP_VARTYPE_STRING: |
| 134 // TODO(brettw) in the case of an invalid string ID, it would be nice |
| 135 // to send something to the other side such that a 0 ID would be |
| 136 // generated there. Then the function implementing the interface can |
| 137 // handle the invalid string as if it was in process rather than seeing |
| 138 // what looks like a valid empty string. |
| 139 m->WriteString(string_value_); |
| 140 break; |
| 141 case PP_VARTYPE_OBJECT: |
| 142 m->WriteInt64(var_.value.as_id); |
| 143 break; |
| 144 } |
| 145 } |
| 146 |
| 147 bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, void** iter) { |
| 148 #ifndef NDEBUG |
| 149 // We should only deserialize something once or will end up with leaked |
| 150 // references. |
| 151 // |
| 152 // One place this has happened in the past is using |
| 153 // std::vector<SerializedVar>.resize(). If you're doing this manually instead |
| 154 // of using the helper classes for handling in/out vectors of vars, be |
| 155 // sure you use the same pattern as the SerializedVarVector classes. |
| 156 DCHECK(!has_been_deserialized_); |
| 157 has_been_deserialized_ = true; |
| 158 #endif |
| 159 |
| 160 // When reading, the dispatcher should be set when we get a Deserialize |
| 161 // call (which will supply a dispatcher). |
| 162 int type; |
| 163 if (!m->ReadInt(iter, &type)) |
| 164 return false; |
| 165 |
| 166 bool success = false; |
| 167 switch (type) { |
| 168 case PP_VARTYPE_UNDEFINED: |
| 169 case PP_VARTYPE_NULL: |
| 170 // These don't have any data associated with them other than the type we |
| 171 // just serialized. |
| 172 success = true; |
| 173 break; |
| 174 case PP_VARTYPE_BOOL: |
| 175 success = m->ReadBool(iter, &var_.value.as_bool); |
| 176 break; |
| 177 case PP_VARTYPE_INT32: |
| 178 success = m->ReadInt(iter, &var_.value.as_int); |
| 179 break; |
| 180 case PP_VARTYPE_DOUBLE: |
| 181 success = IPC::ParamTraits<double>::Read(m, iter, &var_.value.as_double); |
| 182 break; |
| 183 case PP_VARTYPE_STRING: |
| 184 success = m->ReadString(iter, &string_value_); |
| 185 var_.value.as_id = 0; |
| 186 break; |
| 187 case PP_VARTYPE_OBJECT: |
| 188 success = m->ReadInt64(iter, &var_.value.as_id); |
| 189 break; |
| 190 default: |
| 191 // Leave success as false. |
| 192 break; |
| 193 } |
| 194 |
| 195 // All success cases get here. We avoid writing the type above so that the |
| 196 // output param is untouched (defaults to VARTYPE_UNDEFINED) even in the |
| 197 // failure case. |
| 198 if (success) |
| 199 var_.type = static_cast<PP_VarType>(type); |
| 200 return success; |
| 201 } |
| 202 |
| 203 // SerializedVar --------------------------------------------------------------- |
| 204 |
| 205 SerializedVar::SerializedVar() : inner_(new Inner) { |
| 206 } |
| 207 |
| 208 SerializedVar::SerializedVar(VarSerializationRules* serialization_rules) |
| 209 : inner_(new Inner(serialization_rules)) { |
| 210 } |
| 211 |
| 212 SerializedVar::SerializedVar(VarSerializationRules* serialization_rules, |
| 213 const PP_Var& var) |
| 214 : inner_(new Inner(serialization_rules, var)) { |
| 215 } |
| 216 |
| 217 SerializedVar::~SerializedVar() { |
| 218 } |
| 219 |
| 220 // SerializedVarSendInput ------------------------------------------------------ |
| 221 |
| 222 SerializedVarSendInput::SerializedVarSendInput(Dispatcher* dispatcher, |
| 223 const PP_Var& var) |
| 224 : SerializedVar(dispatcher->serialization_rules(), var) { |
| 225 dispatcher->serialization_rules()->SendCallerOwned(var, |
| 226 inner_->GetStringPtr()); |
| 227 } |
| 228 |
| 229 // static |
| 230 void SerializedVarSendInput::ConvertVector(Dispatcher* dispatcher, |
| 231 const PP_Var* input, |
| 232 size_t input_count, |
| 233 std::vector<SerializedVar>* output) { |
| 234 output->resize(input_count); |
| 235 for (size_t i = 0; i < input_count; i++) { |
| 236 (*output)[i] = SerializedVar(dispatcher->serialization_rules(), input[i]); |
| 237 dispatcher->serialization_rules()->SendCallerOwned( |
| 238 input[i], (*output)[i].inner_->GetStringPtr()); |
| 239 } |
| 240 } |
| 241 |
| 242 // ReceiveSerializedVarReturnValue --------------------------------------------- |
| 243 |
| 244 ReceiveSerializedVarReturnValue::ReceiveSerializedVarReturnValue() { |
| 245 } |
| 246 |
| 247 PP_Var ReceiveSerializedVarReturnValue::Return(Dispatcher* dispatcher) { |
| 248 inner_->set_serialization_rules(dispatcher->serialization_rules()); |
| 249 inner_->SetVar(inner_->serialization_rules()->ReceivePassRef( |
| 250 inner_->GetIncompleteVar(), inner_->GetString())); |
| 251 return inner_->GetVar(); |
| 252 } |
| 253 |
| 254 // ReceiveSerializedException -------------------------------------------------- |
| 255 |
| 256 ReceiveSerializedException::ReceiveSerializedException(Dispatcher* dispatcher, |
| 257 PP_Var* exception) |
| 258 : SerializedVar(dispatcher->serialization_rules()), |
| 259 exception_(exception) { |
| 260 } |
| 261 |
| 262 ReceiveSerializedException::~ReceiveSerializedException() { |
| 263 if (exception_) { |
| 264 // When an output exception is specified, it will take ownership of the |
| 265 // reference. |
| 266 inner_->SetVar(inner_->serialization_rules()->ReceivePassRef( |
| 267 inner_->GetIncompleteVar(), inner_->GetString())); |
| 268 *exception_ = inner_->GetVar(); |
| 269 } else { |
| 270 // When no output exception is specified, the browser thinks we have a ref |
| 271 // to an object that we don't want (this will happen only in the plugin |
| 272 // since the browser will always specify an out exception for the plugin to |
| 273 // write into). |
| 274 // |
| 275 // Strings don't need this handling since we can just avoid creating a |
| 276 // Var from the std::string in the first place. |
| 277 if (inner_->GetVar().type == PP_VARTYPE_OBJECT) |
| 278 inner_->serialization_rules()->ReleaseObjectRef(inner_->GetVar()); |
| 279 } |
| 280 } |
| 281 |
| 282 bool ReceiveSerializedException::IsThrown() const { |
| 283 return exception_ && exception_->type != PP_VARTYPE_UNDEFINED; |
| 284 } |
| 285 |
| 286 // ReceiveSerializedVarVectorOutParam ------------------------------------------ |
| 287 |
| 288 ReceiveSerializedVarVectorOutParam::ReceiveSerializedVarVectorOutParam( |
| 289 Dispatcher* dispatcher, |
| 290 uint32_t* output_count, |
| 291 PP_Var** output) |
| 292 : dispatcher_(dispatcher), |
| 293 output_count_(output_count), |
| 294 output_(output) { |
| 295 } |
| 296 |
| 297 ReceiveSerializedVarVectorOutParam::~ReceiveSerializedVarVectorOutParam() { |
| 298 *output_count_ = static_cast<uint32_t>(vector_.size()); |
| 299 if (!vector_.size()) { |
| 300 *output_ = NULL; |
| 301 return; |
| 302 } |
| 303 |
| 304 *output_ = static_cast<PP_Var*>(malloc(vector_.size() * sizeof(PP_Var))); |
| 305 for (size_t i = 0; i < vector_.size(); i++) { |
| 306 // Here we just mimic what happens when returning a value. |
| 307 ReceiveSerializedVarReturnValue converted; |
| 308 SerializedVar* serialized = &converted; |
| 309 *serialized = vector_[i]; |
| 310 (*output_)[i] = converted.Return(dispatcher_); |
| 311 } |
| 312 } |
| 313 |
| 314 std::vector<SerializedVar>* ReceiveSerializedVarVectorOutParam::OutParam() { |
| 315 return &vector_; |
| 316 } |
| 317 |
| 318 // SerializedVarReceiveInput --------------------------------------------------- |
| 319 |
| 320 SerializedVarReceiveInput::SerializedVarReceiveInput( |
| 321 const SerializedVar& serialized) |
| 322 : serialized_(serialized), |
| 323 dispatcher_(NULL), |
| 324 var_(PP_MakeUndefined()) { |
| 325 } |
| 326 |
| 327 SerializedVarReceiveInput::~SerializedVarReceiveInput() { |
| 328 } |
| 329 |
| 330 PP_Var SerializedVarReceiveInput::Get(Dispatcher* dispatcher) { |
| 331 serialized_.inner_->set_serialization_rules( |
| 332 dispatcher->serialization_rules()); |
| 333 |
| 334 // Ensure that when the serialized var goes out of scope it cleans up the |
| 335 // stuff we're making in BeginReceiveCallerOwned. |
| 336 serialized_.inner_->set_cleanup_mode(SerializedVar::END_RECEIVE_CALLER_OWNED); |
| 337 |
| 338 serialized_.inner_->SetVar( |
| 339 serialized_.inner_->serialization_rules()->BeginReceiveCallerOwned( |
| 340 serialized_.inner_->GetIncompleteVar(), |
| 341 serialized_.inner_->GetStringPtr())); |
| 342 return serialized_.inner_->GetVar(); |
| 343 } |
| 344 |
| 345 // SerializedVarVectorReceiveInput --------------------------------------------- |
| 346 |
| 347 SerializedVarVectorReceiveInput::SerializedVarVectorReceiveInput( |
| 348 const std::vector<SerializedVar>& serialized) |
| 349 : serialized_(serialized) { |
| 350 } |
| 351 |
| 352 SerializedVarVectorReceiveInput::~SerializedVarVectorReceiveInput() { |
| 353 for (size_t i = 0; i < deserialized_.size(); i++) { |
| 354 serialized_[i].inner_->serialization_rules()->EndReceiveCallerOwned( |
| 355 deserialized_[i]); |
| 356 } |
| 357 } |
| 358 |
| 359 PP_Var* SerializedVarVectorReceiveInput::Get(Dispatcher* dispatcher, |
| 360 uint32_t* array_size) { |
| 361 deserialized_.resize(serialized_.size()); |
| 362 for (size_t i = 0; i < serialized_.size(); i++) { |
| 363 // The vector must be able to clean themselves up after this call is |
| 364 // torn down. |
| 365 serialized_[i].inner_->set_serialization_rules( |
| 366 dispatcher->serialization_rules()); |
| 367 |
| 368 serialized_[i].inner_->SetVar( |
| 369 serialized_[i].inner_->serialization_rules()->BeginReceiveCallerOwned( |
| 370 serialized_[i].inner_->GetIncompleteVar(), |
| 371 serialized_[i].inner_->GetStringPtr())); |
| 372 deserialized_[i] = serialized_[i].inner_->GetVar(); |
| 373 } |
| 374 |
| 375 *array_size = static_cast<uint32_t>(serialized_.size()); |
| 376 return deserialized_.size() > 0 ? &deserialized_[0] : NULL; |
| 377 } |
| 378 |
| 379 // SerializedVarReturnValue ---------------------------------------------------- |
| 380 |
| 381 SerializedVarReturnValue::SerializedVarReturnValue(SerializedVar* serialized) |
| 382 : serialized_(serialized) { |
| 383 } |
| 384 |
| 385 void SerializedVarReturnValue::Return(Dispatcher* dispatcher, |
| 386 const PP_Var& var) { |
| 387 serialized_->inner_->set_serialization_rules( |
| 388 dispatcher->serialization_rules()); |
| 389 serialized_->inner_->SetVar(var); |
| 390 |
| 391 // Var must clean up after our BeginSendPassRef call. |
| 392 serialized_->inner_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF); |
| 393 |
| 394 dispatcher->serialization_rules()->BeginSendPassRef( |
| 395 serialized_->inner_->GetIncompleteVar(), |
| 396 serialized_->inner_->GetStringPtr()); |
| 397 } |
| 398 |
| 399 // SerializedVarOutParam ------------------------------------------------------- |
| 400 |
| 401 SerializedVarOutParam::SerializedVarOutParam(SerializedVar* serialized) |
| 402 : serialized_(serialized), |
| 403 writable_var_(PP_MakeUndefined()) { |
| 404 } |
| 405 |
| 406 SerializedVarOutParam::~SerializedVarOutParam() { |
| 407 if (serialized_->inner_->serialization_rules()) { |
| 408 // When unset, OutParam wasn't called. We'll just leave the var untouched |
| 409 // in that case. |
| 410 serialized_->inner_->SetVar(writable_var_); |
| 411 serialized_->inner_->serialization_rules()->BeginSendPassRef( |
| 412 writable_var_, serialized_->inner_->GetStringPtr()); |
| 413 |
| 414 // Normally the current object will be created on the stack to wrap a |
| 415 // SerializedVar and won't have a scope around the actual IPC send. So we |
| 416 // need to tell the SerializedVar to do the begin/end send pass ref calls. |
| 417 serialized_->inner_->set_cleanup_mode(SerializedVar::END_SEND_PASS_REF); |
| 418 } |
| 419 } |
| 420 |
| 421 PP_Var* SerializedVarOutParam::OutParam(Dispatcher* dispatcher) { |
| 422 serialized_->inner_->set_serialization_rules( |
| 423 dispatcher->serialization_rules()); |
| 424 return &writable_var_; |
| 425 } |
| 426 |
| 427 // SerializedVarVectorOutParam ------------------------------------------------- |
| 428 |
| 429 SerializedVarVectorOutParam::SerializedVarVectorOutParam( |
| 430 std::vector<SerializedVar>* serialized) |
| 431 : dispatcher_(NULL), |
| 432 serialized_(serialized), |
| 433 count_(0), |
| 434 array_(NULL) { |
| 435 } |
| 436 |
| 437 SerializedVarVectorOutParam::~SerializedVarVectorOutParam() { |
| 438 DCHECK(dispatcher_); |
| 439 |
| 440 // Convert the array written by the pepper code to the serialized structure. |
| 441 // Note we can't use resize here, we have to allocate a new SerializedVar |
| 442 // for each serialized item. See ParamTraits<vector<SerializedVar>>::Read. |
| 443 serialized_->reserve(count_); |
| 444 for (uint32_t i = 0; i < count_; i++) { |
| 445 // Just mimic what we do for regular OutParams. |
| 446 SerializedVar var; |
| 447 SerializedVarOutParam out(&var); |
| 448 *out.OutParam(dispatcher_) = array_[i]; |
| 449 serialized_->push_back(var); |
| 450 } |
| 451 |
| 452 // When returning arrays, the pepper code expects the caller to take |
| 453 // ownership of the array. |
| 454 free(array_); |
| 455 } |
| 456 |
| 457 PP_Var** SerializedVarVectorOutParam::ArrayOutParam(Dispatcher* dispatcher) { |
| 458 DCHECK(!dispatcher_); // Should only be called once. |
| 459 dispatcher_ = dispatcher; |
| 460 return &array_; |
| 461 } |
| 462 |
| 463 } // namespace proxy |
| 464 } // namespace pp |
| 465 |
OLD | NEW |