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/ppapi_globals.h"
26 #include "ppapi/shared_impl/ppb_var_shared.h"
27 #include "ppapi/shared_impl/proxy_lock.h"
28 #include "ppapi/shared_impl/var.h"
35 // Used to do get the set-up information for calling a var object. If the
36 // exception is set, returns NULL. Otherwise, computes the dispatcher for the
37 // given var object. If the var is not a valid object, returns NULL and sets
39 PluginDispatcher
* CheckExceptionAndGetDispatcher(const PP_Var
& object
,
41 // If an exception is already set, we don't need to do anything, just return
42 // an error to the caller.
43 if (exception
&& exception
->type
!= PP_VARTYPE_UNDEFINED
)
47 if (object
.type
== PP_VARTYPE_OBJECT
) {
48 // Get the dispatcher for the object.
49 PluginDispatcher
* dispatcher
=
50 PluginGlobals::Get()->plugin_var_tracker()->
51 DispatcherForPluginObject(object
);
56 // The object is invalid. This means we can't figure out which dispatcher
57 // to use, which is OK because the call will fail anyway. Set the exception.
59 *exception
= StringVar::StringToPPVar(
60 std::string("Attempting to use an invalid object"));
65 // PPB_Var_Deprecated plugin ---------------------------------------------------
67 bool HasProperty(PP_Var var
,
71 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, exception
);
75 ReceiveSerializedException
se(dispatcher
, exception
);
76 PP_Bool result
= PP_FALSE
;
78 dispatcher
->Send(new PpapiHostMsg_PPBVar_HasProperty(
79 API_ID_PPB_VAR_DEPRECATED
,
80 SerializedVarSendInput(dispatcher
, var
),
81 SerializedVarSendInput(dispatcher
, name
), &se
, &result
));
83 return PP_ToBool(result
);
86 bool HasMethod(PP_Var var
,
90 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, exception
);
94 ReceiveSerializedException
se(dispatcher
, exception
);
95 PP_Bool result
= PP_FALSE
;
97 dispatcher
->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated(
98 API_ID_PPB_VAR_DEPRECATED
,
99 SerializedVarSendInput(dispatcher
, var
),
100 SerializedVarSendInput(dispatcher
, name
), &se
, &result
));
102 return PP_ToBool(result
);
105 PP_Var
GetProperty(PP_Var var
,
109 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, exception
);
111 return PP_MakeUndefined();
113 ReceiveSerializedException
se(dispatcher
, exception
);
114 ReceiveSerializedVarReturnValue result
;
115 if (!se
.IsThrown()) {
116 dispatcher
->Send(new PpapiHostMsg_PPBVar_GetProperty(
117 API_ID_PPB_VAR_DEPRECATED
,
118 SerializedVarSendInput(dispatcher
, var
),
119 SerializedVarSendInput(dispatcher
, name
), &se
, &result
));
121 return result
.Return(dispatcher
);
124 void EnumerateProperties(PP_Var var
,
125 uint32_t* property_count
,
129 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, exception
);
136 ReceiveSerializedVarVectorOutParam
out_vector(dispatcher
,
137 property_count
, properties
);
138 ReceiveSerializedException
se(dispatcher
, exception
);
139 if (!se
.IsThrown()) {
140 dispatcher
->Send(new PpapiHostMsg_PPBVar_EnumerateProperties(
141 API_ID_PPB_VAR_DEPRECATED
,
142 SerializedVarSendInput(dispatcher
, var
),
143 out_vector
.OutParam(), &se
));
147 void SetProperty(PP_Var var
,
152 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, exception
);
156 ReceiveSerializedException
se(dispatcher
, exception
);
157 if (!se
.IsThrown()) {
158 dispatcher
->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated(
159 API_ID_PPB_VAR_DEPRECATED
,
160 SerializedVarSendInput(dispatcher
, var
),
161 SerializedVarSendInput(dispatcher
, name
),
162 SerializedVarSendInput(dispatcher
, value
), &se
));
166 void RemoveProperty(PP_Var var
,
170 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, exception
);
174 ReceiveSerializedException
se(dispatcher
, exception
);
175 PP_Bool result
= PP_FALSE
;
176 if (!se
.IsThrown()) {
177 dispatcher
->Send(new PpapiHostMsg_PPBVar_DeleteProperty(
178 API_ID_PPB_VAR_DEPRECATED
,
179 SerializedVarSendInput(dispatcher
, var
),
180 SerializedVarSendInput(dispatcher
, name
), &se
, &result
));
184 PP_Var
Call(PP_Var object
,
190 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(object
, exception
);
192 return PP_MakeUndefined();
194 ReceiveSerializedVarReturnValue result
;
195 ReceiveSerializedException
se(dispatcher
, exception
);
196 if (!se
.IsThrown()) {
197 std::vector
<SerializedVar
> argv_vect
;
198 SerializedVarSendInput::ConvertVector(dispatcher
, argv
, argc
, &argv_vect
);
200 dispatcher
->Send(new PpapiHostMsg_PPBVar_CallDeprecated(
201 API_ID_PPB_VAR_DEPRECATED
,
202 SerializedVarSendInput(dispatcher
, object
),
203 SerializedVarSendInput(dispatcher
, method_name
), argv_vect
,
206 return result
.Return(dispatcher
);
209 PP_Var
Construct(PP_Var object
,
214 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(object
, exception
);
216 return PP_MakeUndefined();
218 ReceiveSerializedVarReturnValue result
;
219 ReceiveSerializedException
se(dispatcher
, exception
);
220 if (!se
.IsThrown()) {
221 std::vector
<SerializedVar
> argv_vect
;
222 SerializedVarSendInput::ConvertVector(dispatcher
, argv
, argc
, &argv_vect
);
224 dispatcher
->Send(new PpapiHostMsg_PPBVar_Construct(
225 API_ID_PPB_VAR_DEPRECATED
,
226 SerializedVarSendInput(dispatcher
, object
),
227 argv_vect
, &se
, &result
));
229 return result
.Return(dispatcher
);
232 bool IsInstanceOf(PP_Var var
,
233 const PPP_Class_Deprecated
* ppp_class
,
234 void** ppp_class_data
) {
236 Dispatcher
* dispatcher
= CheckExceptionAndGetDispatcher(var
, NULL
);
240 PP_Bool result
= PP_FALSE
;
241 int64 class_int
= static_cast<int64
>(reinterpret_cast<intptr_t>(ppp_class
));
242 int64 class_data_int
= 0;
243 dispatcher
->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated(
244 API_ID_PPB_VAR_DEPRECATED
, SerializedVarSendInput(dispatcher
, var
),
245 class_int
, &class_data_int
, &result
));
247 reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int
));
248 return PP_ToBool(result
);
251 PP_Var
CreateObject(PP_Instance instance
,
252 const PPP_Class_Deprecated
* ppp_class
,
253 void* ppp_class_data
) {
255 Dispatcher
* dispatcher
= PluginDispatcher::GetForInstance(instance
);
257 return PP_MakeUndefined();
259 PluginVarTracker
* tracker
= PluginGlobals::Get()->plugin_var_tracker();
260 if (tracker
->IsPluginImplementedObjectAlive(ppp_class_data
))
261 return PP_MakeUndefined(); // Object already exists with this user data.
263 ReceiveSerializedVarReturnValue result
;
264 int64 class_int
= static_cast<int64
>(reinterpret_cast<intptr_t>(ppp_class
));
266 static_cast<int64
>(reinterpret_cast<intptr_t>(ppp_class_data
));
267 dispatcher
->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated(
268 API_ID_PPB_VAR_DEPRECATED
, instance
, class_int
, data_int
,
270 PP_Var ret_var
= result
.Return(dispatcher
);
272 // Register this object as being implemented by the plugin.
273 if (ret_var
.type
== PP_VARTYPE_OBJECT
) {
274 tracker
->PluginImplementedObjectCreated(instance
, ret_var
,
275 ppp_class
, ppp_class_data
);
282 PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy(
283 Dispatcher
* dispatcher
)
284 : InterfaceProxy(dispatcher
),
286 task_factory_(this) {
287 if (!dispatcher
->IsPlugin()) {
288 ppb_var_impl_
= static_cast<const PPB_Var_Deprecated
*>(
289 dispatcher
->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE
));
293 PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() {
297 const PPB_Var_Deprecated
* PPB_Var_Deprecated_Proxy::GetProxyInterface() {
298 static const PPB_Var_Deprecated var_deprecated_interface
= {
299 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef
,
300 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release
,
301 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8
,
302 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8
,
306 &EnumerateProperties
,
314 return &var_deprecated_interface
;
317 bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message
& msg
) {
318 if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV
))
321 // Prevent the dispatcher from going away during a call to Call or other
322 // function that could mutate the DOM. This must happen OUTSIDE of
323 // the message handlers since the SerializedVars use the dispatcher upon
324 // return of the function (converting the SerializedVarReturnValue/OutParam
325 // to a SerializedVar in the destructor).
326 ScopedModuleReference
death_grip(dispatcher());
329 IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy
, msg
)
330 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject
, OnMsgAddRefObject
)
331 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject
, OnMsgReleaseObject
)
332 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty
,
334 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated
,
335 OnMsgHasMethodDeprecated
)
336 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty
,
338 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty
,
340 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties
,
341 OnMsgEnumerateProperties
)
342 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated
,
343 OnMsgSetPropertyDeprecated
)
344 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated
,
346 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct
,
348 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated
,
349 OnMsgIsInstanceOfDeprecated
)
350 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated
,
351 OnMsgCreateObjectDeprecated
)
352 IPC_MESSAGE_UNHANDLED(handled
= false)
353 IPC_END_MESSAGE_MAP()
354 // TODO(brettw) handle bad messages!
358 void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id
) {
359 PP_Var var
= { PP_VARTYPE_OBJECT
};
360 var
.value
.as_id
= object_id
;
361 ppb_var_impl_
->AddRef(var
);
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
383 PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostNonNestableTask(
385 RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject
,
386 task_factory_
.GetWeakPtr(),
390 void PPB_Var_Deprecated_Proxy::OnMsgHasProperty(
391 SerializedVarReceiveInput var
,
392 SerializedVarReceiveInput name
,
393 SerializedVarOutParam exception
,
395 SetAllowPluginReentrancy();
396 *result
= PP_FromBool(ppb_var_impl_
->HasProperty(
397 var
.Get(dispatcher()),
398 name
.Get(dispatcher()),
399 exception
.OutParam(dispatcher())));
402 void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated(
403 SerializedVarReceiveInput var
,
404 SerializedVarReceiveInput name
,
405 SerializedVarOutParam exception
,
407 SetAllowPluginReentrancy();
408 *result
= PP_FromBool(ppb_var_impl_
->HasMethod(
409 var
.Get(dispatcher()),
410 name
.Get(dispatcher()),
411 exception
.OutParam(dispatcher())));
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())));
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()));
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()));
447 void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty(
448 SerializedVarReceiveInput var
,
449 SerializedVarReceiveInput name
,
450 SerializedVarOutParam exception
,
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.
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()),
474 exception
.OutParam(dispatcher())));
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())));
490 void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated(
491 SerializedVarReceiveInput var
,
493 int64
* ppp_class_data
,
495 SetAllowPluginReentrancy();
496 *result
= PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_
,
497 var
.Get(dispatcher()),
502 void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated(
503 PP_Instance instance
,
506 SerializedVarReturnValue result
) {
507 SetAllowPluginReentrancy();
508 result
.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject(
509 ppb_var_impl_
, dispatcher(), instance
, ppp_class
, class_data
));
512 void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
513 if (dispatcher()->IsPlugin())
516 static_cast<HostDispatcher
*>(dispatcher())->set_allow_plugin_reentrancy();
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
);