Home | History | Annotate | Download | only in proxy
      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 }  // namespace
    280 
    281 PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy(
    282     Dispatcher* dispatcher)
    283     : InterfaceProxy(dispatcher),
    284       ppb_var_impl_(NULL),
    285       task_factory_(this) {
    286   if (!dispatcher->IsPlugin()) {
    287     ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>(
    288         dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE));
    289   }
    290 }
    291 
    292 PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() {
    293 }
    294 
    295 // static
    296 const PPB_Var_Deprecated* PPB_Var_Deprecated_Proxy::GetProxyInterface() {
    297   static const PPB_Var_Deprecated var_deprecated_interface = {
    298     ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
    299     ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
    300     ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
    301     ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
    302     &HasProperty,
    303     &HasMethod,
    304     &GetProperty,
    305     &EnumerateProperties,
    306     &SetProperty,
    307     &RemoveProperty,
    308     &Call,
    309     &Construct,
    310     &IsInstanceOf,
    311     &CreateObject
    312   };
    313   return &var_deprecated_interface;
    314 }
    315 
    316 bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) {
    317   if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV))
    318     return false;
    319 
    320   // Prevent the dispatcher from going away during a call to Call or other
    321   // function that could mutate the DOM. This must happen OUTSIDE of
    322   // the message handlers since the SerializedVars use the dispatcher upon
    323   // return of the function (converting the SerializedVarReturnValue/OutParam
    324   // to a SerializedVar in the destructor).
    325   ScopedModuleReference death_grip(dispatcher());
    326 
    327   bool handled = true;
    328   IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg)
    329     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject)
    330     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject)
    331     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty,
    332                         OnMsgHasProperty)
    333     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated,
    334                         OnMsgHasMethodDeprecated)
    335     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty,
    336                         OnMsgGetProperty)
    337     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty,
    338                         OnMsgDeleteProperty)
    339     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties,
    340                         OnMsgEnumerateProperties)
    341     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated,
    342                         OnMsgSetPropertyDeprecated)
    343     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated,
    344                         OnMsgCallDeprecated)
    345     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct,
    346                         OnMsgConstruct)
    347     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated,
    348                         OnMsgIsInstanceOfDeprecated)
    349     IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated,
    350                         OnMsgCreateObjectDeprecated)
    351     IPC_MESSAGE_UNHANDLED(handled = false)
    352   IPC_END_MESSAGE_MAP()
    353   // TODO(brettw) handle bad messages!
    354   return handled;
    355 }
    356 
    357 void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id,
    358                                                  int* /* unused */) {
    359   PP_Var var = { PP_VARTYPE_OBJECT };
    360   var.value.as_id = object_id;
    361   ppb_var_impl_->AddRef(var);
    362 }
    363 
    364 void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64 object_id) {
    365   // Ok, so this is super subtle.
    366   // When the browser side sends a sync IPC message that returns a var, and the
    367   // plugin wants to give ownership of that var to the browser, dropping all
    368   // references, it may call ReleaseObject right after returning the result.
    369   // However, the IPC system doesn't enforce strict ordering of messages in that
    370   // case, where a message that is set to unblock (e.g. a sync message, or in
    371   // our case all messages coming from the plugin) that is sent *after* the
    372   // result may be dispatched on the browser side *before* the sync send
    373   // returned (see ipc_sync_channel.cc). In this case, that means it could
    374   // release the object before it is AddRef'ed on the browser side.
    375   // To work around this, we post a task here, that will not execute before
    376   // control goes back to the main message loop, that will ensure the sync send
    377   // has returned and the browser side can take its reference before we Release.
    378   // Note: if the instance is gone by the time the task is executed, then it
    379   // will Release the objects itself and this Release will be a NOOP (aside of a
    380   // spurious warning).
    381   // TODO(piman): See if we can fix the IPC code to enforce strict ordering, and
    382   // then remove this.
    383   base::MessageLoop::current()->PostNonNestableTask(
    384       FROM_HERE,
    385       RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject,
    386                                 task_factory_.GetWeakPtr(),
    387                                 object_id)));
    388 }
    389 
    390 void PPB_Var_Deprecated_Proxy::OnMsgHasProperty(
    391     SerializedVarReceiveInput var,
    392     SerializedVarReceiveInput name,
    393     SerializedVarOutParam exception,
    394     PP_Bool* result) {
    395   SetAllowPluginReentrancy();
    396   *result = PP_FromBool(ppb_var_impl_->HasProperty(
    397       var.Get(dispatcher()),
    398       name.Get(dispatcher()),
    399       exception.OutParam(dispatcher())));
    400 }
    401 
    402 void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated(
    403     SerializedVarReceiveInput var,
    404     SerializedVarReceiveInput name,
    405     SerializedVarOutParam exception,
    406     PP_Bool* result) {
    407   SetAllowPluginReentrancy();
    408   *result = PP_FromBool(ppb_var_impl_->HasMethod(
    409       var.Get(dispatcher()),
    410       name.Get(dispatcher()),
    411       exception.OutParam(dispatcher())));
    412 }
    413 
    414 void PPB_Var_Deprecated_Proxy::OnMsgGetProperty(
    415     SerializedVarReceiveInput var,
    416     SerializedVarReceiveInput name,
    417     SerializedVarOutParam exception,
    418     SerializedVarReturnValue result) {
    419   SetAllowPluginReentrancy();
    420   result.Return(dispatcher(), ppb_var_impl_->GetProperty(
    421       var.Get(dispatcher()), name.Get(dispatcher()),
    422       exception.OutParam(dispatcher())));
    423 }
    424 
    425 void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties(
    426     SerializedVarReceiveInput var,
    427     SerializedVarVectorOutParam props,
    428     SerializedVarOutParam exception) {
    429   SetAllowPluginReentrancy();
    430   ppb_var_impl_->GetAllPropertyNames(var.Get(dispatcher()),
    431       props.CountOutParam(), props.ArrayOutParam(dispatcher()),
    432       exception.OutParam(dispatcher()));
    433 }
    434 
    435 void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated(
    436     SerializedVarReceiveInput var,
    437     SerializedVarReceiveInput name,
    438     SerializedVarReceiveInput value,
    439     SerializedVarOutParam exception) {
    440   SetAllowPluginReentrancy();
    441   ppb_var_impl_->SetProperty(var.Get(dispatcher()),
    442                                 name.Get(dispatcher()),
    443                                 value.Get(dispatcher()),
    444                                 exception.OutParam(dispatcher()));
    445 }
    446 
    447 void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty(
    448     SerializedVarReceiveInput var,
    449     SerializedVarReceiveInput name,
    450     SerializedVarOutParam exception,
    451     PP_Bool* result) {
    452   SetAllowPluginReentrancy();
    453   ppb_var_impl_->RemoveProperty(var.Get(dispatcher()),
    454                                    name.Get(dispatcher()),
    455                                    exception.OutParam(dispatcher()));
    456   // This deprecated function doesn't actually return a value, but we re-use
    457   // the message from the non-deprecated interface with the return value.
    458   *result = PP_TRUE;
    459 }
    460 
    461 void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated(
    462     SerializedVarReceiveInput object,
    463     SerializedVarReceiveInput method_name,
    464     SerializedVarVectorReceiveInput arg_vector,
    465     SerializedVarOutParam exception,
    466     SerializedVarReturnValue result) {
    467   SetAllowPluginReentrancy();
    468   uint32_t arg_count = 0;
    469   PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
    470   result.Return(dispatcher(), ppb_var_impl_->Call(
    471       object.Get(dispatcher()),
    472       method_name.Get(dispatcher()),
    473       arg_count, args,
    474       exception.OutParam(dispatcher())));
    475 }
    476 
    477 void PPB_Var_Deprecated_Proxy::OnMsgConstruct(
    478     SerializedVarReceiveInput var,
    479     SerializedVarVectorReceiveInput arg_vector,
    480     SerializedVarOutParam exception,
    481     SerializedVarReturnValue result) {
    482   SetAllowPluginReentrancy();
    483   uint32_t arg_count = 0;
    484   PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
    485   result.Return(dispatcher(), ppb_var_impl_->Construct(
    486       var.Get(dispatcher()), arg_count, args,
    487       exception.OutParam(dispatcher())));
    488 }
    489 
    490 void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated(
    491     SerializedVarReceiveInput var,
    492     int64 ppp_class,
    493     int64* ppp_class_data,
    494     PP_Bool* result) {
    495   SetAllowPluginReentrancy();
    496   *result = PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_,
    497                                           var.Get(dispatcher()),
    498                                           ppp_class,
    499                                           ppp_class_data);
    500 }
    501 
    502 void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated(
    503     PP_Instance instance,
    504     int64 ppp_class,
    505     int64 class_data,
    506     SerializedVarReturnValue result) {
    507   SetAllowPluginReentrancy();
    508   result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject(
    509       ppb_var_impl_, dispatcher(), instance, ppp_class, class_data));
    510 }
    511 
    512 void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
    513   if (dispatcher()->IsPlugin())
    514     NOTREACHED();
    515   else
    516     static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy();
    517 }
    518 
    519 void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id) {
    520   PP_Var var = { PP_VARTYPE_OBJECT };
    521   var.value.as_id = object_id;
    522   ppb_var_impl_->Release(var);
    523 }
    524 
    525 }  // namespace proxy
    526 }  // namespace ppapi
    527