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.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"
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
),
288 task_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(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
));
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 MessageLoop::current()->PostNonNestableTask(FROM_HERE
,
396 RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject
,
397 task_factory_
.GetWeakPtr(),
401 void PPB_Var_Deprecated_Proxy::OnMsgHasProperty(
402 SerializedVarReceiveInput var
,
403 SerializedVarReceiveInput name
,
404 SerializedVarOutParam exception
,
406 SetAllowPluginReentrancy();
407 *result
= PP_FromBool(ppb_var_impl_
->HasProperty(
408 var
.Get(dispatcher()),
409 name
.Get(dispatcher()),
410 exception
.OutParam(dispatcher())));
413 void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated(
414 SerializedVarReceiveInput var
,
415 SerializedVarReceiveInput name
,
416 SerializedVarOutParam exception
,
418 SetAllowPluginReentrancy();
419 *result
= PP_FromBool(ppb_var_impl_
->HasMethod(
420 var
.Get(dispatcher()),
421 name
.Get(dispatcher()),
422 exception
.OutParam(dispatcher())));
425 void PPB_Var_Deprecated_Proxy::OnMsgGetProperty(
426 SerializedVarReceiveInput var
,
427 SerializedVarReceiveInput name
,
428 SerializedVarOutParam exception
,
429 SerializedVarReturnValue result
) {
430 SetAllowPluginReentrancy();
431 result
.Return(dispatcher(), ppb_var_impl_
->GetProperty(
432 var
.Get(dispatcher()), name
.Get(dispatcher()),
433 exception
.OutParam(dispatcher())));
436 void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties(
437 SerializedVarReceiveInput var
,
438 SerializedVarVectorOutParam props
,
439 SerializedVarOutParam exception
) {
440 SetAllowPluginReentrancy();
441 ppb_var_impl_
->GetAllPropertyNames(var
.Get(dispatcher()),
442 props
.CountOutParam(), props
.ArrayOutParam(dispatcher()),
443 exception
.OutParam(dispatcher()));
446 void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated(
447 SerializedVarReceiveInput var
,
448 SerializedVarReceiveInput name
,
449 SerializedVarReceiveInput value
,
450 SerializedVarOutParam exception
) {
451 SetAllowPluginReentrancy();
452 ppb_var_impl_
->SetProperty(var
.Get(dispatcher()),
453 name
.Get(dispatcher()),
454 value
.Get(dispatcher()),
455 exception
.OutParam(dispatcher()));
458 void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty(
459 SerializedVarReceiveInput var
,
460 SerializedVarReceiveInput name
,
461 SerializedVarOutParam exception
,
463 SetAllowPluginReentrancy();
464 ppb_var_impl_
->RemoveProperty(var
.Get(dispatcher()),
465 name
.Get(dispatcher()),
466 exception
.OutParam(dispatcher()));
467 // This deprecated function doesn't actually return a value, but we re-use
468 // the message from the non-deprecated interface with the return value.
472 void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated(
473 SerializedVarReceiveInput object
,
474 SerializedVarReceiveInput method_name
,
475 SerializedVarVectorReceiveInput arg_vector
,
476 SerializedVarOutParam exception
,
477 SerializedVarReturnValue result
) {
478 SetAllowPluginReentrancy();
479 uint32_t arg_count
= 0;
480 PP_Var
* args
= arg_vector
.Get(dispatcher(), &arg_count
);
481 result
.Return(dispatcher(), ppb_var_impl_
->Call(
482 object
.Get(dispatcher()),
483 method_name
.Get(dispatcher()),
485 exception
.OutParam(dispatcher())));
488 void PPB_Var_Deprecated_Proxy::OnMsgConstruct(
489 SerializedVarReceiveInput var
,
490 SerializedVarVectorReceiveInput arg_vector
,
491 SerializedVarOutParam exception
,
492 SerializedVarReturnValue result
) {
493 SetAllowPluginReentrancy();
494 uint32_t arg_count
= 0;
495 PP_Var
* args
= arg_vector
.Get(dispatcher(), &arg_count
);
496 result
.Return(dispatcher(), ppb_var_impl_
->Construct(
497 var
.Get(dispatcher()), arg_count
, args
,
498 exception
.OutParam(dispatcher())));
501 void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated(
502 SerializedVarReceiveInput var
,
504 int64
* ppp_class_data
,
506 SetAllowPluginReentrancy();
507 *result
= PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_
,
508 var
.Get(dispatcher()),
513 void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated(
514 PP_Instance instance
,
517 SerializedVarReturnValue result
) {
518 SetAllowPluginReentrancy();
519 result
.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject(
520 ppb_var_impl_
, dispatcher(), instance
, ppp_class
, class_data
));
523 void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
524 if (dispatcher()->IsPlugin())
527 static_cast<HostDispatcher
*>(dispatcher())->set_allow_plugin_reentrancy();
530 void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id
) {
531 PP_Var var
= { PP_VARTYPE_OBJECT
};
532 var
.value
.as_id
= object_id
;
533 ppb_var_impl_
->Release(var
);