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/plugin_resource.h"
9 #include "ppapi/proxy/ppapi_messages.h"
14 PluginResource::PluginResource(Connection connection
, PP_Instance instance
)
15 : Resource(OBJECT_IS_PROXY
, instance
),
16 connection_(connection
),
17 next_sequence_number_(1),
18 sent_create_to_browser_(false),
19 sent_create_to_renderer_(false) {
22 PluginResource::~PluginResource() {
23 if (sent_create_to_browser_
) {
24 connection_
.browser_sender
->Send(
25 new PpapiHostMsg_ResourceDestroyed(pp_resource()));
27 if (sent_create_to_renderer_
) {
28 connection_
.renderer_sender
->Send(
29 new PpapiHostMsg_ResourceDestroyed(pp_resource()));
33 void PluginResource::OnReplyReceived(
34 const proxy::ResourceMessageReplyParams
& params
,
35 const IPC::Message
& msg
) {
36 // Grab the callback for the reply sequence number and run it with |msg|.
37 CallbackMap::iterator it
= callbacks_
.find(params
.sequence());
38 if (it
== callbacks_
.end()) {
39 DCHECK(false) << "Callback does not exist for an expected sequence number.";
41 scoped_refptr
<PluginResourceCallbackBase
> callback
= it
->second
;
43 callback
->Run(params
, msg
);
47 void PluginResource::NotifyLastPluginRefWasDeleted() {
48 Resource::NotifyLastPluginRefWasDeleted();
50 // The callbacks may hold referrences to this object. Normally, we will get
51 // reply messages from the host side and remove them. However, it is possible
52 // that some replies from the host never arrive, e.g., the corresponding
53 // renderer crashes. In that case, we have to clean up the callbacks,
54 // otherwise this object will live forever.
58 void PluginResource::NotifyInstanceWasDeleted() {
59 Resource::NotifyInstanceWasDeleted();
61 // Please see comments in NotifyLastPluginRefWasDeleted() about why we must
62 // clean up the callbacks.
63 // It is possible that NotifyLastPluginRefWasDeleted() is never called for a
64 // resource. For example, those singleton-style resources such as
65 // GamepadResource never expose references to the plugin and thus won't
66 // receive a NotifyLastPluginRefWasDeleted() call. For those resources, we
67 // need to clean up callbacks when the instance goes away.
71 void PluginResource::SendCreate(Destination dest
, const IPC::Message
& msg
) {
72 if (dest
== RENDERER
) {
73 DCHECK(!sent_create_to_renderer_
);
74 sent_create_to_renderer_
= true;
76 DCHECK(!sent_create_to_browser_
);
77 sent_create_to_browser_
= true;
79 ResourceMessageCallParams
params(pp_resource(), GetNextSequence());
80 GetSender(dest
)->Send(
81 new PpapiHostMsg_ResourceCreated(params
, pp_instance(), msg
));
84 void PluginResource::AttachToPendingHost(Destination dest
,
85 int pending_host_id
) {
86 // Connecting to a pending host is a replacement for "create".
87 if (dest
== RENDERER
) {
88 DCHECK(!sent_create_to_renderer_
);
89 sent_create_to_renderer_
= true;
91 DCHECK(!sent_create_to_browser_
);
92 sent_create_to_browser_
= true;
94 GetSender(dest
)->Send(
95 new PpapiHostMsg_AttachToPendingHost(pp_resource(), pending_host_id
));
98 void PluginResource::Post(Destination dest
, const IPC::Message
& msg
) {
99 ResourceMessageCallParams
params(pp_resource(), GetNextSequence());
100 SendResourceCall(dest
, params
, msg
);
103 bool PluginResource::SendResourceCall(
105 const ResourceMessageCallParams
& call_params
,
106 const IPC::Message
& nested_msg
) {
107 return GetSender(dest
)->Send(
108 new PpapiHostMsg_ResourceCall(call_params
, nested_msg
));
111 int32_t PluginResource::GenericSyncCall(
113 const IPC::Message
& msg
,
115 ResourceMessageReplyParams
* reply_params
) {
116 ResourceMessageCallParams
params(pp_resource(), GetNextSequence());
117 params
.set_has_callback();
118 bool success
= GetSender(dest
)->Send(new PpapiHostMsg_ResourceSyncCall(
119 params
, msg
, reply_params
, reply
));
121 return reply_params
->result();
122 return PP_ERROR_FAILED
;
125 int32_t PluginResource::GetNextSequence() {
126 // Return the value with wraparound, making sure we don't make a sequence
127 // number with a 0 ID. Note that signed wraparound is undefined in C++ so we
129 int32_t ret
= next_sequence_number_
;
130 if (next_sequence_number_
== std::numeric_limits
<int32_t>::max())
131 next_sequence_number_
= 1; // Skip 0 which is invalid.
133 next_sequence_number_
++;