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/plugin_resource.h"
6
7 #include <limits>
8
9 #include "ppapi/proxy/plugin_globals.h"
10 #include "ppapi/proxy/ppapi_messages.h"
11 #include "ppapi/shared_impl/ppapi_globals.h"
12
13 namespace ppapi {
14 namespace proxy {
15
SafeRunCallback(scoped_refptr<TrackedCallback> * callback,int32_t error)16 void SafeRunCallback(scoped_refptr<TrackedCallback>* callback, int32_t error) {
17 if (TrackedCallback::IsPending(*callback)) {
18 scoped_refptr<TrackedCallback> temp;
19 callback->swap(temp);
20 temp->Run(error);
21 }
22 }
23
PluginResource(Connection connection,PP_Instance instance)24 PluginResource::PluginResource(Connection connection, PP_Instance instance)
25 : Resource(OBJECT_IS_PROXY, instance),
26 connection_(connection),
27 next_sequence_number_(1),
28 sent_create_to_browser_(false),
29 sent_create_to_renderer_(false),
30 resource_reply_thread_registrar_(
31 PpapiGlobals::Get()->IsPluginGlobals() ?
32 PluginGlobals::Get()->resource_reply_thread_registrar() : NULL) {
33 }
34
~PluginResource()35 PluginResource::~PluginResource() {
36 if (sent_create_to_browser_) {
37 connection_.browser_sender()->Send(
38 new PpapiHostMsg_ResourceDestroyed(pp_resource()));
39 }
40 if (sent_create_to_renderer_) {
41 connection_.GetRendererSender()->Send(
42 new PpapiHostMsg_ResourceDestroyed(pp_resource()));
43 }
44
45 if (resource_reply_thread_registrar_.get())
46 resource_reply_thread_registrar_->Unregister(pp_resource());
47 }
48
OnReplyReceived(const proxy::ResourceMessageReplyParams & params,const IPC::Message & msg)49 void PluginResource::OnReplyReceived(
50 const proxy::ResourceMessageReplyParams& params,
51 const IPC::Message& msg) {
52 TRACE_EVENT2("ppapi proxy", "PluginResource::OnReplyReceived",
53 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
54 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
55 // Grab the callback for the reply sequence number and run it with |msg|.
56 CallbackMap::iterator it = callbacks_.find(params.sequence());
57 if (it == callbacks_.end()) {
58 DCHECK(false) << "Callback does not exist for an expected sequence number.";
59 } else {
60 scoped_refptr<PluginResourceCallbackBase> callback = it->second;
61 callbacks_.erase(it);
62 callback->Run(params, msg);
63 }
64 }
65
NotifyLastPluginRefWasDeleted()66 void PluginResource::NotifyLastPluginRefWasDeleted() {
67 Resource::NotifyLastPluginRefWasDeleted();
68
69 // The callbacks may hold referrences to this object. Normally, we will get
70 // reply messages from the host side and remove them. However, it is possible
71 // that some replies from the host never arrive, e.g., the corresponding
72 // renderer crashes. In that case, we have to clean up the callbacks,
73 // otherwise this object will live forever.
74 callbacks_.clear();
75 }
76
NotifyInstanceWasDeleted()77 void PluginResource::NotifyInstanceWasDeleted() {
78 Resource::NotifyInstanceWasDeleted();
79
80 // Please see comments in NotifyLastPluginRefWasDeleted() about why we must
81 // clean up the callbacks.
82 // It is possible that NotifyLastPluginRefWasDeleted() is never called for a
83 // resource. For example, those singleton-style resources such as
84 // GamepadResource never expose references to the plugin and thus won't
85 // receive a NotifyLastPluginRefWasDeleted() call. For those resources, we
86 // need to clean up callbacks when the instance goes away.
87 callbacks_.clear();
88 }
89
SendCreate(Destination dest,const IPC::Message & msg)90 void PluginResource::SendCreate(Destination dest, const IPC::Message& msg) {
91 TRACE_EVENT2("ppapi proxy", "PluginResource::SendCreate",
92 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
93 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
94 if (dest == RENDERER) {
95 DCHECK(!sent_create_to_renderer_);
96 sent_create_to_renderer_ = true;
97 } else {
98 DCHECK(!sent_create_to_browser_);
99 sent_create_to_browser_ = true;
100 }
101 ResourceMessageCallParams params(pp_resource(), GetNextSequence());
102 GetSender(dest)->Send(
103 new PpapiHostMsg_ResourceCreated(params, pp_instance(), msg));
104 }
105
AttachToPendingHost(Destination dest,int pending_host_id)106 void PluginResource::AttachToPendingHost(Destination dest,
107 int pending_host_id) {
108 // Connecting to a pending host is a replacement for "create".
109 if (dest == RENDERER) {
110 DCHECK(!sent_create_to_renderer_);
111 sent_create_to_renderer_ = true;
112 } else {
113 DCHECK(!sent_create_to_browser_);
114 sent_create_to_browser_ = true;
115 }
116 GetSender(dest)->Send(
117 new PpapiHostMsg_AttachToPendingHost(pp_resource(), pending_host_id));
118 }
119
Post(Destination dest,const IPC::Message & msg)120 void PluginResource::Post(Destination dest, const IPC::Message& msg) {
121 TRACE_EVENT2("ppapi proxy", "PluginResource::Post",
122 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
123 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
124 ResourceMessageCallParams params(pp_resource(), GetNextSequence());
125 SendResourceCall(dest, params, msg);
126 }
127
SendResourceCall(Destination dest,const ResourceMessageCallParams & call_params,const IPC::Message & nested_msg)128 bool PluginResource::SendResourceCall(
129 Destination dest,
130 const ResourceMessageCallParams& call_params,
131 const IPC::Message& nested_msg) {
132 // For in-process plugins, we need to send the routing ID with the request.
133 // The browser then uses that routing ID when sending the reply so it will be
134 // routed back to the correct RenderFrameImpl.
135 if (dest == BROWSER && connection_.in_process()) {
136 return GetSender(dest)->Send(new PpapiHostMsg_InProcessResourceCall(
137 connection_.browser_sender_routing_id(), call_params, nested_msg));
138 } else {
139 return GetSender(dest)->Send(
140 new PpapiHostMsg_ResourceCall(call_params, nested_msg));
141 }
142 }
143
GenericSyncCall(Destination dest,const IPC::Message & msg,IPC::Message * reply,ResourceMessageReplyParams * reply_params)144 int32_t PluginResource::GenericSyncCall(
145 Destination dest,
146 const IPC::Message& msg,
147 IPC::Message* reply,
148 ResourceMessageReplyParams* reply_params) {
149 TRACE_EVENT2("ppapi proxy", "PluginResource::GenericSyncCall",
150 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
151 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
152 ResourceMessageCallParams params(pp_resource(), GetNextSequence());
153 params.set_has_callback();
154 bool success = GetSender(dest)->Send(new PpapiHostMsg_ResourceSyncCall(
155 params, msg, reply_params, reply));
156 if (success)
157 return reply_params->result();
158 return PP_ERROR_FAILED;
159 }
160
GetNextSequence()161 int32_t PluginResource::GetNextSequence() {
162 // Return the value with wraparound, making sure we don't make a sequence
163 // number with a 0 ID. Note that signed wraparound is undefined in C++ so we
164 // manually check.
165 int32_t ret = next_sequence_number_;
166 if (next_sequence_number_ == std::numeric_limits<int32_t>::max())
167 next_sequence_number_ = 1; // Skip 0 which is invalid.
168 else
169 next_sequence_number_++;
170 return ret;
171 }
172
173 } // namespace proxy
174 } // namespace ppapi
175