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.
5 #include "ppapi/proxy/ppb_var_deprecated_proxy.h"
7 #include <stdlib.h> // For malloc
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"
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
38 PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object,
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)
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);
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.
58 *exception = StringVar::StringToPPVar(
59 std::string("Attempting to use an invalid object"));
64 // PPB_Var_Deprecated plugin ---------------------------------------------------
66 bool HasProperty(PP_Var var,
70 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
74 ReceiveSerializedException se(dispatcher, exception);
75 PP_Bool result = PP_FALSE;
77 dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty(
78 API_ID_PPB_VAR_DEPRECATED,
79 SerializedVarSendInput(dispatcher, var),
80 SerializedVarSendInput(dispatcher, name), &se, &result));
82 return PP_ToBool(result);
85 bool HasMethod(PP_Var var,
89 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
93 ReceiveSerializedException se(dispatcher, exception);
94 PP_Bool result = PP_FALSE;
96 dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated(
97 API_ID_PPB_VAR_DEPRECATED,
98 SerializedVarSendInput(dispatcher, var),
99 SerializedVarSendInput(dispatcher, name), &se, &result));
101 return PP_ToBool(result);
104 PP_Var GetProperty(PP_Var var,
108 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
110 return PP_MakeUndefined();
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));
120 return result.Return(dispatcher);
123 void EnumerateProperties(PP_Var var,
124 uint32_t* property_count,
128 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
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));
146 void SetProperty(PP_Var var,
151 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
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));
165 void RemoveProperty(PP_Var var,
169 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
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));
183 PP_Var Call(PP_Var object,
189 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception);
191 return PP_MakeUndefined();
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);
199 dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated(
200 API_ID_PPB_VAR_DEPRECATED,
201 SerializedVarSendInput(dispatcher, object),
202 SerializedVarSendInput(dispatcher, method_name), argv_vect,
205 return result.Return(dispatcher);
208 PP_Var Construct(PP_Var object,
213 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception);
215 return PP_MakeUndefined();
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);
223 dispatcher->Send(new PpapiHostMsg_PPBVar_Construct(
224 API_ID_PPB_VAR_DEPRECATED,
225 SerializedVarSendInput(dispatcher, object),
226 argv_vect, &se, &result));
228 return result.Return(dispatcher);
231 bool IsInstanceOf(PP_Var var,
232 const PPP_Class_Deprecated* ppp_class,
233 void** ppp_class_data) {
235 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL);
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));
246 reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int));
247 return PP_ToBool(result);
250 PP_Var CreateObject(PP_Instance instance,
251 const PPP_Class_Deprecated* ppp_class,
252 void* ppp_class_data) {
254 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
256 return PP_MakeUndefined();
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.
262 ReceiveSerializedVarReturnValue result;
263 int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class));
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,
269 PP_Var ret_var = result.Return(dispatcher);
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);
279 InterfaceProxy* CreateVarDeprecatedProxy(Dispatcher* dispatcher) {
280 return new PPB_Var_Deprecated_Proxy(dispatcher );
285 PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy(
286 Dispatcher* dispatcher)
287 : InterfaceProxy(dispatcher),
289 task_factory_(this) {
290 if (!dispatcher->IsPlugin()) {
291 ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>(
292 dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE));
296 PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() {
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,
309 &EnumerateProperties,
318 static const Info info = {
319 &var_deprecated_interface,
320 PPB_VAR_DEPRECATED_INTERFACE,
321 API_ID_PPB_VAR_DEPRECATED,
323 &CreateVarDeprecatedProxy,
328 bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) {
329 if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV))
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());
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,
345 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated,
346 OnMsgHasMethodDeprecated)
347 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty,
349 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty,
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,
357 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct,
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!
369 void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id,
371 PP_Var var = { PP_VARTYPE_OBJECT };
372 var.value.as_id = object_id;
373 ppb_var_impl_->AddRef(var);
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
395 base::MessageLoop::current()->PostNonNestableTask(
397 RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject,
398 task_factory_.GetWeakPtr(),
402 void PPB_Var_Deprecated_Proxy::OnMsgHasProperty(
403 SerializedVarReceiveInput var,
404 SerializedVarReceiveInput name,
405 SerializedVarOutParam exception,
407 SetAllowPluginReentrancy();
408 *result = PP_FromBool(ppb_var_impl_->HasProperty(
409 var.Get(dispatcher()),
410 name.Get(dispatcher()),
411 exception.OutParam(dispatcher())));
414 void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated(
415 SerializedVarReceiveInput var,
416 SerializedVarReceiveInput name,
417 SerializedVarOutParam exception,
419 SetAllowPluginReentrancy();
420 *result = PP_FromBool(ppb_var_impl_->HasMethod(
421 var.Get(dispatcher()),
422 name.Get(dispatcher()),
423 exception.OutParam(dispatcher())));
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())));
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()));
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()));
459 void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty(
460 SerializedVarReceiveInput var,
461 SerializedVarReceiveInput name,
462 SerializedVarOutParam exception,
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.
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()),
486 exception.OutParam(dispatcher())));
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())));
502 void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated(
503 SerializedVarReceiveInput var,
505 int64* ppp_class_data,
507 SetAllowPluginReentrancy();
508 *result = PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_,
509 var.Get(dispatcher()),
514 void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated(
515 PP_Instance instance,
518 SerializedVarReturnValue result) {
519 SetAllowPluginReentrancy();
520 result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject(
521 ppb_var_impl_, dispatcher(), instance, ppp_class, class_data));
524 void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
525 if (dispatcher()->IsPlugin())
528 static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy();
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);