| // 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. |
| |
| #include "ppapi/proxy/ppb_var_deprecated_proxy.h" |
| |
| #include <stdlib.h> // For malloc |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "ppapi/c/dev/ppb_var_deprecated.h" |
| #include "ppapi/c/pp_var.h" |
| #include "ppapi/c/ppb_core.h" |
| #include "ppapi/c/ppb_var.h" |
| #include "ppapi/proxy/host_dispatcher.h" |
| #include "ppapi/proxy/plugin_dispatcher.h" |
| #include "ppapi/proxy/plugin_globals.h" |
| #include "ppapi/proxy/plugin_resource_tracker.h" |
| #include "ppapi/proxy/plugin_var_tracker.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| #include "ppapi/proxy/ppp_class_proxy.h" |
| #include "ppapi/proxy/proxy_object_var.h" |
| #include "ppapi/proxy/serialized_var.h" |
| #include "ppapi/shared_impl/ppapi_globals.h" |
| #include "ppapi/shared_impl/ppb_var_shared.h" |
| #include "ppapi/shared_impl/proxy_lock.h" |
| #include "ppapi/shared_impl/var.h" |
| |
| namespace ppapi { |
| namespace proxy { |
| |
| namespace { |
| |
| // Used to do get the set-up information for calling a var object. If the |
| // exception is set, returns NULL. Otherwise, computes the dispatcher for the |
| // given var object. If the var is not a valid object, returns NULL and sets |
| // the exception. |
| PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object, |
| PP_Var* exception) { |
| // If an exception is already set, we don't need to do anything, just return |
| // an error to the caller. |
| if (exception && exception->type != PP_VARTYPE_UNDEFINED) |
| return NULL; |
| |
| |
| if (object.type == PP_VARTYPE_OBJECT) { |
| // Get the dispatcher for the object. |
| PluginDispatcher* dispatcher = |
| PluginGlobals::Get()->plugin_var_tracker()-> |
| DispatcherForPluginObject(object); |
| if (dispatcher) |
| return dispatcher; |
| } |
| |
| // The object is invalid. This means we can't figure out which dispatcher |
| // to use, which is OK because the call will fail anyway. Set the exception. |
| if (exception) { |
| *exception = StringVar::StringToPPVar( |
| std::string("Attempting to use an invalid object")); |
| } |
| return NULL; |
| } |
| |
| // PPB_Var_Deprecated plugin --------------------------------------------------- |
| |
| bool HasProperty(PP_Var var, |
| PP_Var name, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); |
| if (!dispatcher) |
| return false; |
| |
| ReceiveSerializedException se(dispatcher, exception); |
| PP_Bool result = PP_FALSE; |
| if (!se.IsThrown()) { |
| dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, var), |
| SerializedVarSendInput(dispatcher, name), &se, &result)); |
| } |
| return PP_ToBool(result); |
| } |
| |
| bool HasMethod(PP_Var var, |
| PP_Var name, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); |
| if (!dispatcher) |
| return false; |
| |
| ReceiveSerializedException se(dispatcher, exception); |
| PP_Bool result = PP_FALSE; |
| if (!se.IsThrown()) { |
| dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, var), |
| SerializedVarSendInput(dispatcher, name), &se, &result)); |
| } |
| return PP_ToBool(result); |
| } |
| |
| PP_Var GetProperty(PP_Var var, |
| PP_Var name, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); |
| if (!dispatcher) |
| return PP_MakeUndefined(); |
| |
| ReceiveSerializedException se(dispatcher, exception); |
| ReceiveSerializedVarReturnValue result; |
| if (!se.IsThrown()) { |
| dispatcher->Send(new PpapiHostMsg_PPBVar_GetProperty( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, var), |
| SerializedVarSendInput(dispatcher, name), &se, &result)); |
| } |
| return result.Return(dispatcher); |
| } |
| |
| void EnumerateProperties(PP_Var var, |
| uint32_t* property_count, |
| PP_Var** properties, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); |
| if (!dispatcher) { |
| *property_count = 0; |
| *properties = NULL; |
| return; |
| } |
| |
| ReceiveSerializedVarVectorOutParam out_vector(dispatcher, |
| property_count, properties); |
| ReceiveSerializedException se(dispatcher, exception); |
| if (!se.IsThrown()) { |
| dispatcher->Send(new PpapiHostMsg_PPBVar_EnumerateProperties( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, var), |
| out_vector.OutParam(), &se)); |
| } |
| } |
| |
| void SetProperty(PP_Var var, |
| PP_Var name, |
| PP_Var value, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); |
| if (!dispatcher) |
| return; |
| |
| ReceiveSerializedException se(dispatcher, exception); |
| if (!se.IsThrown()) { |
| dispatcher->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, var), |
| SerializedVarSendInput(dispatcher, name), |
| SerializedVarSendInput(dispatcher, value), &se)); |
| } |
| } |
| |
| void RemoveProperty(PP_Var var, |
| PP_Var name, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception); |
| if (!dispatcher) |
| return; |
| |
| ReceiveSerializedException se(dispatcher, exception); |
| PP_Bool result = PP_FALSE; |
| if (!se.IsThrown()) { |
| dispatcher->Send(new PpapiHostMsg_PPBVar_DeleteProperty( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, var), |
| SerializedVarSendInput(dispatcher, name), &se, &result)); |
| } |
| } |
| |
| PP_Var Call(PP_Var object, |
| PP_Var method_name, |
| uint32_t argc, |
| PP_Var* argv, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); |
| if (!dispatcher) |
| return PP_MakeUndefined(); |
| |
| ReceiveSerializedVarReturnValue result; |
| ReceiveSerializedException se(dispatcher, exception); |
| if (!se.IsThrown()) { |
| std::vector<SerializedVar> argv_vect; |
| SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); |
| |
| dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, object), |
| SerializedVarSendInput(dispatcher, method_name), argv_vect, |
| &se, &result)); |
| } |
| return result.Return(dispatcher); |
| } |
| |
| PP_Var Construct(PP_Var object, |
| uint32_t argc, |
| PP_Var* argv, |
| PP_Var* exception) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception); |
| if (!dispatcher) |
| return PP_MakeUndefined(); |
| |
| ReceiveSerializedVarReturnValue result; |
| ReceiveSerializedException se(dispatcher, exception); |
| if (!se.IsThrown()) { |
| std::vector<SerializedVar> argv_vect; |
| SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect); |
| |
| dispatcher->Send(new PpapiHostMsg_PPBVar_Construct( |
| API_ID_PPB_VAR_DEPRECATED, |
| SerializedVarSendInput(dispatcher, object), |
| argv_vect, &se, &result)); |
| } |
| return result.Return(dispatcher); |
| } |
| |
| bool IsInstanceOf(PP_Var var, |
| const PPP_Class_Deprecated* ppp_class, |
| void** ppp_class_data) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL); |
| if (!dispatcher) |
| return false; |
| |
| PP_Bool result = PP_FALSE; |
| int64_t class_int = |
| static_cast<int64_t>(reinterpret_cast<intptr_t>(ppp_class)); |
| int64_t class_data_int = 0; |
| dispatcher->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated( |
| API_ID_PPB_VAR_DEPRECATED, SerializedVarSendInput(dispatcher, var), |
| class_int, &class_data_int, &result)); |
| *ppp_class_data = |
| reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int)); |
| return PP_ToBool(result); |
| } |
| |
| PP_Var CreateObject(PP_Instance instance, |
| const PPP_Class_Deprecated* ppp_class, |
| void* ppp_class_data) { |
| ProxyAutoLock lock; |
| Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); |
| if (!dispatcher) |
| return PP_MakeUndefined(); |
| |
| PluginVarTracker* tracker = PluginGlobals::Get()->plugin_var_tracker(); |
| if (tracker->IsPluginImplementedObjectAlive(ppp_class_data)) |
| return PP_MakeUndefined(); // Object already exists with this user data. |
| |
| ReceiveSerializedVarReturnValue result; |
| int64_t class_int = |
| static_cast<int64_t>(reinterpret_cast<intptr_t>(ppp_class)); |
| int64_t data_int = |
| static_cast<int64_t>(reinterpret_cast<intptr_t>(ppp_class_data)); |
| dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated( |
| API_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int, |
| &result)); |
| PP_Var ret_var = result.Return(dispatcher); |
| |
| // Register this object as being implemented by the plugin. |
| if (ret_var.type == PP_VARTYPE_OBJECT) { |
| tracker->PluginImplementedObjectCreated(instance, ret_var, |
| ppp_class, ppp_class_data); |
| } |
| return ret_var; |
| } |
| |
| } // namespace |
| |
| PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy( |
| Dispatcher* dispatcher) |
| : InterfaceProxy(dispatcher), |
| ppb_var_impl_(NULL), |
| task_factory_(this) { |
| if (!dispatcher->IsPlugin()) { |
| ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>( |
| dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE)); |
| } |
| } |
| |
| PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() { |
| } |
| |
| // static |
| const PPB_Var_Deprecated* PPB_Var_Deprecated_Proxy::GetProxyInterface() { |
| static const PPB_Var_Deprecated var_deprecated_interface = { |
| ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef, |
| ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release, |
| ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, |
| ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, |
| &HasProperty, |
| &HasMethod, |
| &GetProperty, |
| &EnumerateProperties, |
| &SetProperty, |
| &RemoveProperty, |
| &Call, |
| &Construct, |
| &IsInstanceOf, |
| &CreateObject |
| }; |
| return &var_deprecated_interface; |
| } |
| |
| bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) { |
| if (!dispatcher()->permissions().HasPermission(PERMISSION_FLASH)) |
| return false; |
| |
| // Prevent the dispatcher from going away during a call to Call or other |
| // function that could mutate the DOM. This must happen OUTSIDE of |
| // the message handlers since the SerializedVars use the dispatcher upon |
| // return of the function (converting the SerializedVarReturnValue/OutParam |
| // to a SerializedVar in the destructor). |
| ScopedModuleReference death_grip(dispatcher()); |
| |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty, |
| OnMsgHasProperty) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated, |
| OnMsgHasMethodDeprecated) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty, |
| OnMsgGetProperty) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty, |
| OnMsgDeleteProperty) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties, |
| OnMsgEnumerateProperties) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated, |
| OnMsgSetPropertyDeprecated) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated, |
| OnMsgCallDeprecated) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct, |
| OnMsgConstruct) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated, |
| OnMsgIsInstanceOfDeprecated) |
| IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated, |
| OnMsgCreateObjectDeprecated) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| // TODO(brettw) handle bad messages! |
| return handled; |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64_t object_id) { |
| PP_Var var = { PP_VARTYPE_OBJECT }; |
| var.value.as_id = object_id; |
| ppb_var_impl_->AddRef(var); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64_t object_id) { |
| // Ok, so this is super subtle. |
| // When the browser side sends a sync IPC message that returns a var, and the |
| // plugin wants to give ownership of that var to the browser, dropping all |
| // references, it may call ReleaseObject right after returning the result. |
| // However, the IPC system doesn't enforce strict ordering of messages in that |
| // case, where a message that is set to unblock (e.g. a sync message, or in |
| // our case all messages coming from the plugin) that is sent *after* the |
| // result may be dispatched on the browser side *before* the sync send |
| // returned (see ipc_sync_channel.cc). In this case, that means it could |
| // release the object before it is AddRef'ed on the browser side. |
| // To work around this, we post a task here, that will not execute before |
| // control goes back to the main message loop, that will ensure the sync send |
| // has returned and the browser side can take its reference before we Release. |
| // Note: if the instance is gone by the time the task is executed, then it |
| // will Release the objects itself and this Release will be a NOOP (aside of a |
| // spurious warning). |
| // TODO(piman): See if we can fix the IPC code to enforce strict ordering, and |
| // then remove this. |
| PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostNonNestableTask( |
| FROM_HERE, |
| RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject, |
| task_factory_.GetWeakPtr(), |
| object_id))); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgHasProperty( |
| SerializedVarReceiveInput var, |
| SerializedVarReceiveInput name, |
| SerializedVarOutParam exception, |
| PP_Bool* result) { |
| SetAllowPluginReentrancy(); |
| *result = PP_FromBool(ppb_var_impl_->HasProperty( |
| var.Get(dispatcher()), |
| name.Get(dispatcher()), |
| exception.OutParam(dispatcher()))); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated( |
| SerializedVarReceiveInput var, |
| SerializedVarReceiveInput name, |
| SerializedVarOutParam exception, |
| PP_Bool* result) { |
| SetAllowPluginReentrancy(); |
| *result = PP_FromBool(ppb_var_impl_->HasMethod( |
| var.Get(dispatcher()), |
| name.Get(dispatcher()), |
| exception.OutParam(dispatcher()))); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgGetProperty( |
| SerializedVarReceiveInput var, |
| SerializedVarReceiveInput name, |
| SerializedVarOutParam exception, |
| SerializedVarReturnValue result) { |
| SetAllowPluginReentrancy(); |
| result.Return(dispatcher(), ppb_var_impl_->GetProperty( |
| var.Get(dispatcher()), name.Get(dispatcher()), |
| exception.OutParam(dispatcher()))); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties( |
| SerializedVarReceiveInput var, |
| SerializedVarVectorOutParam props, |
| SerializedVarOutParam exception) { |
| SetAllowPluginReentrancy(); |
| ppb_var_impl_->GetAllPropertyNames(var.Get(dispatcher()), |
| props.CountOutParam(), props.ArrayOutParam(dispatcher()), |
| exception.OutParam(dispatcher())); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated( |
| SerializedVarReceiveInput var, |
| SerializedVarReceiveInput name, |
| SerializedVarReceiveInput value, |
| SerializedVarOutParam exception) { |
| SetAllowPluginReentrancy(); |
| ppb_var_impl_->SetProperty(var.Get(dispatcher()), |
| name.Get(dispatcher()), |
| value.Get(dispatcher()), |
| exception.OutParam(dispatcher())); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty( |
| SerializedVarReceiveInput var, |
| SerializedVarReceiveInput name, |
| SerializedVarOutParam exception, |
| PP_Bool* result) { |
| SetAllowPluginReentrancy(); |
| ppb_var_impl_->RemoveProperty(var.Get(dispatcher()), |
| name.Get(dispatcher()), |
| exception.OutParam(dispatcher())); |
| // This deprecated function doesn't actually return a value, but we re-use |
| // the message from the non-deprecated interface with the return value. |
| *result = PP_TRUE; |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated( |
| SerializedVarReceiveInput object, |
| SerializedVarReceiveInput method_name, |
| SerializedVarVectorReceiveInput arg_vector, |
| SerializedVarOutParam exception, |
| SerializedVarReturnValue result) { |
| SetAllowPluginReentrancy(); |
| uint32_t arg_count = 0; |
| PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); |
| result.Return(dispatcher(), ppb_var_impl_->Call( |
| object.Get(dispatcher()), |
| method_name.Get(dispatcher()), |
| arg_count, args, |
| exception.OutParam(dispatcher()))); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgConstruct( |
| SerializedVarReceiveInput var, |
| SerializedVarVectorReceiveInput arg_vector, |
| SerializedVarOutParam exception, |
| SerializedVarReturnValue result) { |
| SetAllowPluginReentrancy(); |
| uint32_t arg_count = 0; |
| PP_Var* args = arg_vector.Get(dispatcher(), &arg_count); |
| result.Return(dispatcher(), ppb_var_impl_->Construct( |
| var.Get(dispatcher()), arg_count, args, |
| exception.OutParam(dispatcher()))); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated( |
| SerializedVarReceiveInput var, |
| int64_t ppp_class, |
| int64_t* ppp_class_data, |
| PP_Bool* result) { |
| SetAllowPluginReentrancy(); |
| *result = PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_, |
| var.Get(dispatcher()), |
| ppp_class, |
| ppp_class_data); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated( |
| PP_Instance instance, |
| int64_t ppp_class, |
| int64_t class_data, |
| SerializedVarReturnValue result) { |
| SetAllowPluginReentrancy(); |
| result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject( |
| ppb_var_impl_, dispatcher(), instance, ppp_class, class_data)); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() { |
| if (dispatcher()->IsPlugin()) |
| NOTREACHED(); |
| else |
| static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy(); |
| } |
| |
| void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64_t object_id) { |
| PP_Var var = { PP_VARTYPE_OBJECT }; |
| var.value.as_id = object_id; |
| ppb_var_impl_->Release(var); |
| } |
| |
| } // namespace proxy |
| } // namespace ppapi |