ppb_var_deprecated_proxy.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.h"
12#include "ppapi/c/dev/ppb_var_deprecated.h"
13#include "ppapi/c/pp_var.h"
14#include "ppapi/c/ppb_var.h"
15#include "ppapi/c/ppb_core.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/proxy_object_var.h"
22#include "ppapi/proxy/ppapi_messages.h"
23#include "ppapi/proxy/ppp_class_proxy.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
29namespace ppapi {
30namespace proxy {
31
32namespace {
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.
38PluginDispatcher* 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
66bool 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
85bool 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
104PP_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
123void 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
146void 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
165void 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
183PP_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
208PP_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
231bool 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
250PP_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
279InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher) {
280  return new PPB_Var_Deprecated_Proxy(dispatcher );
281}
282
283}  // namespace
284
285PPB_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
296PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() {
297}
298
299// static
300const 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
328bool 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
369void 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
376void 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
402void 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
414void 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
426void 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
437void 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
447void 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
459void 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
473void 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
489void 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
502void 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
514void 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
524void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
525  if (dispatcher()->IsPlugin())
526    NOTREACHED();
527  else
528    static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy();
529}
530
531void 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