1 // Copyright (c) 2012 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/ppb_var_deprecated_proxy.h" 6 7 #include <stdlib.h> // For malloc 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/message_loop/message_loop.h" 12 #include "ppapi/c/dev/ppb_var_deprecated.h" 13 #include "ppapi/c/pp_var.h" 14 #include "ppapi/c/ppb_core.h" 15 #include "ppapi/c/ppb_var.h" 16 #include "ppapi/proxy/host_dispatcher.h" 17 #include "ppapi/proxy/plugin_dispatcher.h" 18 #include "ppapi/proxy/plugin_globals.h" 19 #include "ppapi/proxy/plugin_resource_tracker.h" 20 #include "ppapi/proxy/plugin_var_tracker.h" 21 #include "ppapi/proxy/ppapi_messages.h" 22 #include "ppapi/proxy/ppp_class_proxy.h" 23 #include "ppapi/proxy/proxy_object_var.h" 24 #include "ppapi/proxy/serialized_var.h" 25 #include "ppapi/shared_impl/ppb_var_shared.h" 26 #include "ppapi/shared_impl/proxy_lock.h" 27 #include "ppapi/shared_impl/var.h" 28 29 namespace ppapi { 30 namespace proxy { 31 32 namespace { 33 34 // Used to do get the set-up information for calling a var object. If the 35 // exception is set, returns NULL. Otherwise, computes the dispatcher for the 36 // given var object. If the var is not a valid object, returns NULL and sets 37 // the exception. 38 PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object, 39 PP_Var* exception) { 40 // If an exception is already set, we don't need to do anything, just return 41 // an error to the caller. 42 if (exception && exception->type != PP_VARTYPE_UNDEFINED) 43 return NULL; 44 45 46 if (object.type == PP_VARTYPE_OBJECT) { 47 // Get the dispatcher for the object. 48 PluginDispatcher* dispatcher = 49 PluginGlobals::Get()->plugin_var_tracker()-> 50 DispatcherForPluginObject(object); 51 if (dispatcher) 52 return dispatcher; 53 } 54 55 // The object is invalid. This means we can't figure out which dispatcher 56 // to use, which is OK because the call will fail anyway. Set the exception. 57 if (exception) { 58 *exception = StringVar::StringToPPVar( 59 std::string("Attempting to use an invalid object")); 60 } 61 return NULL; 62 } 63 64 // PPB_Var_Deprecated plugin --------------------------------------------------- 65 66 bool HasProperty(PP_Var var, 67 PP_Var name, 68 PP_Var* exception) { 69 ProxyAutoLock lock; 70 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); 71 if (!dispatcher) 72 return false; 73 74 ReceiveSerializedException se(dispatcher, exception); 75 PP_Bool result = PP_FALSE; 76 if (!se.IsThrown()) { 77 dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty( 78 API_ID_PPB_VAR_DEPRECATED, 79 SerializedVarSendInput(dispatcher, var), 80 SerializedVarSendInput(dispatcher, name), &se, &result)); 81 } 82 return PP_ToBool(result); 83 } 84 85 bool HasMethod(PP_Var var, 86 PP_Var name, 87 PP_Var* exception) { 88 ProxyAutoLock lock; 89 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); 90 if (!dispatcher) 91 return false; 92 93 ReceiveSerializedException se(dispatcher, exception); 94 PP_Bool result = PP_FALSE; 95 if (!se.IsThrown()) { 96 dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated( 97 API_ID_PPB_VAR_DEPRECATED, 98 SerializedVarSendInput(dispatcher, var), 99 SerializedVarSendInput(dispatcher, name), &se, &result)); 100 } 101 return PP_ToBool(result); 102 } 103 104 PP_Var GetProperty(PP_Var var, 105 PP_Var name, 106 PP_Var* exception) { 107 ProxyAutoLock lock; 108 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); 109 if (!dispatcher) 110 return PP_MakeUndefined(); 111 112 ReceiveSerializedException se(dispatcher, exception); 113 ReceiveSerializedVarReturnValue result; 114 if (!se.IsThrown()) { 115 dispatcher->Send(new PpapiHostMsg_PPBVar_GetProperty( 116 API_ID_PPB_VAR_DEPRECATED, 117 SerializedVarSendInput(dispatcher, var), 118 SerializedVarSendInput(dispatcher, name), &se, &result)); 119 } 120 return result.Return(dispatcher); 121 } 122 123 void EnumerateProperties(PP_Var var, 124 uint32_t* property_count, 125 PP_Var** properties, 126 PP_Var* exception) { 127 ProxyAutoLock lock; 128 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); 129 if (!dispatcher) { 130 *property_count = 0; 131 *properties = NULL; 132 return; 133 } 134 135 ReceiveSerializedVarVectorOutParam out_vector(dispatcher, 136 property_count, properties); 137 ReceiveSerializedException se(dispatcher, exception); 138 if (!se.IsThrown()) { 139 dispatcher->Send(new PpapiHostMsg_PPBVar_EnumerateProperties( 140 API_ID_PPB_VAR_DEPRECATED, 141 SerializedVarSendInput(dispatcher, var), 142 out_vector.OutParam(), &se)); 143 } 144 } 145 146 void SetProperty(PP_Var var, 147 PP_Var name, 148 PP_Var value, 149 PP_Var* exception) { 150 ProxyAutoLock lock; 151 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); 152 if (!dispatcher) 153 return; 154 155 ReceiveSerializedException se(dispatcher, exception); 156 if (!se.IsThrown()) { 157 dispatcher->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated( 158 API_ID_PPB_VAR_DEPRECATED, 159 SerializedVarSendInput(dispatcher, var), 160 SerializedVarSendInput(dispatcher, name), 161 SerializedVarSendInput(dispatcher, value), &se)); 162 } 163 } 164 165 void RemoveProperty(PP_Var var, 166 PP_Var name, 167 PP_Var* exception) { 168 ProxyAutoLock lock; 169 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); 170 if (!dispatcher) 171 return; 172 173 ReceiveSerializedException se(dispatcher, exception); 174 PP_Bool result = PP_FALSE; 175 if (!se.IsThrown()) { 176 dispatcher->Send(new PpapiHostMsg_PPBVar_DeleteProperty( 177 API_ID_PPB_VAR_DEPRECATED, 178 SerializedVarSendInput(dispatcher, var), 179 SerializedVarSendInput(dispatcher, name), &se, &result)); 180 } 181 } 182 183 PP_Var Call(PP_Var object, 184 PP_Var method_name, 185 uint32_t argc, 186 PP_Var* argv, 187 PP_Var* exception) { 188 ProxyAutoLock lock; 189 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); 190 if (!dispatcher) 191 return PP_MakeUndefined(); 192 193 ReceiveSerializedVarReturnValue result; 194 ReceiveSerializedException se(dispatcher, exception); 195 if (!se.IsThrown()) { 196 std::vector<SerializedVar> argv_vect; 197 SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); 198 199 dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated( 200 API_ID_PPB_VAR_DEPRECATED, 201 SerializedVarSendInput(dispatcher, object), 202 SerializedVarSendInput(dispatcher, method_name), argv_vect, 203 &se, &result)); 204 } 205 return result.Return(dispatcher); 206 } 207 208 PP_Var Construct(PP_Var object, 209 uint32_t argc, 210 PP_Var* argv, 211 PP_Var* exception) { 212 ProxyAutoLock lock; 213 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); 214 if (!dispatcher) 215 return PP_MakeUndefined(); 216 217 ReceiveSerializedVarReturnValue result; 218 ReceiveSerializedException se(dispatcher, exception); 219 if (!se.IsThrown()) { 220 std::vector<SerializedVar> argv_vect; 221 SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); 222 223 dispatcher->Send(new PpapiHostMsg_PPBVar_Construct( 224 API_ID_PPB_VAR_DEPRECATED, 225 SerializedVarSendInput(dispatcher, object), 226 argv_vect, &se, &result)); 227 } 228 return result.Return(dispatcher); 229 } 230 231 bool IsInstanceOf(PP_Var var, 232 const PPP_Class_Deprecated* ppp_class, 233 void** ppp_class_data) { 234 ProxyAutoLock lock; 235 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL); 236 if (!dispatcher) 237 return false; 238 239 PP_Bool result = PP_FALSE; 240 int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); 241 int64 class_data_int = 0; 242 dispatcher->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated( 243 API_ID_PPB_VAR_DEPRECATED, SerializedVarSendInput(dispatcher, var), 244 class_int, &class_data_int, &result)); 245 *ppp_class_data = 246 reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int)); 247 return PP_ToBool(result); 248 } 249 250 PP_Var CreateObject(PP_Instance instance, 251 const PPP_Class_Deprecated* ppp_class, 252 void* ppp_class_data) { 253 ProxyAutoLock lock; 254 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); 255 if (!dispatcher) 256 return PP_MakeUndefined(); 257 258 PluginVarTracker* tracker = PluginGlobals::Get()->plugin_var_tracker(); 259 if (tracker->IsPluginImplementedObjectAlive(ppp_class_data)) 260 return PP_MakeUndefined(); // Object already exists with this user data. 261 262 ReceiveSerializedVarReturnValue result; 263 int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class)); 264 int64 data_int = 265 static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class_data)); 266 dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated( 267 API_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int, 268 &result)); 269 PP_Var ret_var = result.Return(dispatcher); 270 271 // Register this object as being implemented by the plugin. 272 if (ret_var.type == PP_VARTYPE_OBJECT) { 273 tracker->PluginImplementedObjectCreated(instance, ret_var, 274 ppp_class, ppp_class_data); 275 } 276 return ret_var; 277 } 278 279 InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher) { 280 return new PPB_Var_Deprecated_Proxy(dispatcher ); 281 } 282 283 } // namespace 284 285 PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy( 286 Dispatcher* dispatcher) 287 : InterfaceProxy(dispatcher), 288 task_factory_(this), 289 ppb_var_impl_(NULL) { 290 if (!dispatcher->IsPlugin()) { 291 ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>( 292 dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE)); 293 } 294 } 295 296 PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() { 297 } 298 299 // static 300 const InterfaceProxy::Info* PPB_Var_Deprecated_Proxy::GetInfo() { 301 static const PPB_Var_Deprecated var_deprecated_interface = { 302 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef, 303 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release, 304 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, 305 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, 306 &HasProperty, 307 &HasMethod, 308 &GetProperty, 309 &EnumerateProperties, 310 &SetProperty, 311 &RemoveProperty, 312 &Call, 313 &Construct, 314 &IsInstanceOf, 315 &CreateObject 316 }; 317 318 static const Info info = { 319 &var_deprecated_interface, 320 PPB_VAR_DEPRECATED_INTERFACE, 321 API_ID_PPB_VAR_DEPRECATED, 322 false, 323 &CreateVarDeprecatedProxy, 324 }; 325 return &info; 326 } 327 328 bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) { 329 if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV)) 330 return false; 331 332 // Prevent the dispatcher from going away during a call to Call or other 333 // function that could mutate the DOM. This must happen OUTSIDE of 334 // the message handlers since the SerializedVars use the dispatcher upon 335 // return of the function (converting the SerializedVarReturnValue/OutParam 336 // to a SerializedVar in the destructor). 337 ScopedModuleReference death_grip(dispatcher()); 338 339 bool handled = true; 340 IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg) 341 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject) 342 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject) 343 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty, 344 OnMsgHasProperty) 345 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated, 346 OnMsgHasMethodDeprecated) 347 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty, 348 OnMsgGetProperty) 349 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty, 350 OnMsgDeleteProperty) 351 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties, 352 OnMsgEnumerateProperties) 353 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated, 354 OnMsgSetPropertyDeprecated) 355 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated, 356 OnMsgCallDeprecated) 357 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct, 358 OnMsgConstruct) 359 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated, 360 OnMsgIsInstanceOfDeprecated) 361 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated, 362 OnMsgCreateObjectDeprecated) 363 IPC_MESSAGE_UNHANDLED(handled = false) 364 IPC_END_MESSAGE_MAP() 365 // TODO(brettw) handle bad messages! 366 return handled; 367 } 368 369 void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id, 370 int* /* unused */) { 371 PP_Var var = { PP_VARTYPE_OBJECT }; 372 var.value.as_id = object_id; 373 ppb_var_impl_->AddRef(var); 374 } 375 376 void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64 object_id) { 377 // Ok, so this is super subtle. 378 // When the browser side sends a sync IPC message that returns a var, and the 379 // plugin wants to give ownership of that var to the browser, dropping all 380 // references, it may call ReleaseObject right after returning the result. 381 // However, the IPC system doesn't enforce strict ordering of messages in that 382 // case, where a message that is set to unblock (e.g. a sync message, or in 383 // our case all messages coming from the plugin) that is sent *after* the 384 // result may be dispatched on the browser side *before* the sync send 385 // returned (see ipc_sync_channel.cc). In this case, that means it could 386 // release the object before it is AddRef'ed on the browser side. 387 // To work around this, we post a task here, that will not execute before 388 // control goes back to the main message loop, that will ensure the sync send 389 // has returned and the browser side can take its reference before we Release. 390 // Note: if the instance is gone by the time the task is executed, then it 391 // will Release the objects itself and this Release will be a NOOP (aside of a 392 // spurious warning). 393 // TODO(piman): See if we can fix the IPC code to enforce strict ordering, and 394 // then remove this. 395 base::MessageLoop::current()->PostNonNestableTask( 396 FROM_HERE, 397 RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject, 398 task_factory_.GetWeakPtr(), 399 object_id))); 400 } 401 402 void PPB_Var_Deprecated_Proxy::OnMsgHasProperty( 403 SerializedVarReceiveInput var, 404 SerializedVarReceiveInput name, 405 SerializedVarOutParam exception, 406 PP_Bool* result) { 407 SetAllowPluginReentrancy(); 408 *result = PP_FromBool(ppb_var_impl_->HasProperty( 409 var.Get(dispatcher()), 410 name.Get(dispatcher()), 411 exception.OutParam(dispatcher()))); 412 } 413 414 void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated( 415 SerializedVarReceiveInput var, 416 SerializedVarReceiveInput name, 417 SerializedVarOutParam exception, 418 PP_Bool* result) { 419 SetAllowPluginReentrancy(); 420 *result = PP_FromBool(ppb_var_impl_->HasMethod( 421 var.Get(dispatcher()), 422 name.Get(dispatcher()), 423 exception.OutParam(dispatcher()))); 424 } 425 426 void PPB_Var_Deprecated_Proxy::OnMsgGetProperty( 427 SerializedVarReceiveInput var, 428 SerializedVarReceiveInput name, 429 SerializedVarOutParam exception, 430 SerializedVarReturnValue result) { 431 SetAllowPluginReentrancy(); 432 result.Return(dispatcher(), ppb_var_impl_->GetProperty( 433 var.Get(dispatcher()), name.Get(dispatcher()), 434 exception.OutParam(dispatcher()))); 435 } 436 437 void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties( 438 SerializedVarReceiveInput var, 439 SerializedVarVectorOutParam props, 440 SerializedVarOutParam exception) { 441 SetAllowPluginReentrancy(); 442 ppb_var_impl_->GetAllPropertyNames(var.Get(dispatcher()), 443 props.CountOutParam(), props.ArrayOutParam(dispatcher()), 444 exception.OutParam(dispatcher())); 445 } 446 447 void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated( 448 SerializedVarReceiveInput var, 449 SerializedVarReceiveInput name, 450 SerializedVarReceiveInput value, 451 SerializedVarOutParam exception) { 452 SetAllowPluginReentrancy(); 453 ppb_var_impl_->SetProperty(var.Get(dispatcher()), 454 name.Get(dispatcher()), 455 value.Get(dispatcher()), 456 exception.OutParam(dispatcher())); 457 } 458 459 void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty( 460 SerializedVarReceiveInput var, 461 SerializedVarReceiveInput name, 462 SerializedVarOutParam exception, 463 PP_Bool* result) { 464 SetAllowPluginReentrancy(); 465 ppb_var_impl_->RemoveProperty(var.Get(dispatcher()), 466 name.Get(dispatcher()), 467 exception.OutParam(dispatcher())); 468 // This deprecated function doesn't actually return a value, but we re-use 469 // the message from the non-deprecated interface with the return value. 470 *result = PP_TRUE; 471 } 472 473 void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated( 474 SerializedVarReceiveInput object, 475 SerializedVarReceiveInput method_name, 476 SerializedVarVectorReceiveInput arg_vector, 477 SerializedVarOutParam exception, 478 SerializedVarReturnValue result) { 479 SetAllowPluginReentrancy(); 480 uint32_t arg_count = 0; 481 PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); 482 result.Return(dispatcher(), ppb_var_impl_->Call( 483 object.Get(dispatcher()), 484 method_name.Get(dispatcher()), 485 arg_count, args, 486 exception.OutParam(dispatcher()))); 487 } 488 489 void PPB_Var_Deprecated_Proxy::OnMsgConstruct( 490 SerializedVarReceiveInput var, 491 SerializedVarVectorReceiveInput arg_vector, 492 SerializedVarOutParam exception, 493 SerializedVarReturnValue result) { 494 SetAllowPluginReentrancy(); 495 uint32_t arg_count = 0; 496 PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); 497 result.Return(dispatcher(), ppb_var_impl_->Construct( 498 var.Get(dispatcher()), arg_count, args, 499 exception.OutParam(dispatcher()))); 500 } 501 502 void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated( 503 SerializedVarReceiveInput var, 504 int64 ppp_class, 505 int64* ppp_class_data, 506 PP_Bool* result) { 507 SetAllowPluginReentrancy(); 508 *result = PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_, 509 var.Get(dispatcher()), 510 ppp_class, 511 ppp_class_data); 512 } 513 514 void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated( 515 PP_Instance instance, 516 int64 ppp_class, 517 int64 class_data, 518 SerializedVarReturnValue result) { 519 SetAllowPluginReentrancy(); 520 result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject( 521 ppb_var_impl_, dispatcher(), instance, ppp_class, class_data)); 522 } 523 524 void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() { 525 if (dispatcher()->IsPlugin()) 526 NOTREACHED(); 527 else 528 static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); 529 } 530 531 void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id) { 532 PP_Var var = { PP_VARTYPE_OBJECT }; 533 var.value.as_id = object_id; 534 ppb_var_impl_->Release(var); 535 } 536 537 } // namespace proxy 538 } // namespace ppapi 539