Make sure GN deps rolls include the optional GN bots.
[chromium-blink-merge.git] / ppapi / host / ppapi_host.cc
blobfa312bb69b0b0d301f1850c097ee7fd514428864
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/host/ppapi_host.h"
7 #include "base/logging.h"
8 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/host/host_factory.h"
10 #include "ppapi/host/host_message_context.h"
11 #include "ppapi/host/instance_message_filter.h"
12 #include "ppapi/host/resource_host.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14 #include "ppapi/proxy/resource_message_params.h"
15 #include "ppapi/proxy/serialized_handle.h"
16 #include "ppapi/shared_impl/host_resource.h"
18 namespace ppapi {
19 namespace host {
21 using proxy::SerializedHandle;
23 namespace {
25 // Put a cap on the maximum number of resources so we don't explode if the
26 // renderer starts spamming us.
27 const size_t kMaxResourcesPerPlugin = 1 << 14;
29 } // namespace
31 PpapiHost::PpapiHost(IPC::Sender* sender,
32 const PpapiPermissions& perms)
33 : sender_(sender),
34 permissions_(perms),
35 next_pending_resource_host_id_(1) {
38 PpapiHost::~PpapiHost() {
39 // Delete these explicitly before destruction since then the host is still
40 // technically alive in case one of the filters accesses us from the
41 // destructor.
42 instance_message_filters_.clear();
44 // The resources may also want to use us in their destructors.
45 resources_.clear();
46 pending_resource_hosts_.clear();
49 bool PpapiHost::Send(IPC::Message* msg) {
50 return sender_->Send(msg);
53 bool PpapiHost::OnMessageReceived(const IPC::Message& msg) {
54 bool handled = true;
55 IPC_BEGIN_MESSAGE_MAP(PpapiHost, msg)
56 IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceCall,
57 OnHostMsgResourceCall)
58 IPC_MESSAGE_HANDLER(PpapiHostMsg_InProcessResourceCall,
59 OnHostMsgInProcessResourceCall)
60 IPC_MESSAGE_HANDLER_DELAY_REPLY(PpapiHostMsg_ResourceSyncCall,
61 OnHostMsgResourceSyncCall)
62 IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceCreated,
63 OnHostMsgResourceCreated)
64 IPC_MESSAGE_HANDLER(PpapiHostMsg_AttachToPendingHost,
65 OnHostMsgAttachToPendingHost)
66 IPC_MESSAGE_HANDLER(PpapiHostMsg_ResourceDestroyed,
67 OnHostMsgResourceDestroyed)
68 IPC_MESSAGE_UNHANDLED(handled = false)
69 IPC_END_MESSAGE_MAP()
71 if (!handled) {
72 for (size_t i = 0; i < instance_message_filters_.size(); i++) {
73 if (instance_message_filters_[i]->OnInstanceMessageReceived(msg)) {
74 handled = true;
75 break;
80 return handled;
83 void PpapiHost::SendReply(const ReplyMessageContext& context,
84 const IPC::Message& msg) {
85 TRACE_EVENT2("ppapi proxy", "PpapiHost::SendReply",
86 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
87 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
88 if (context.sync_reply_msg) {
89 PpapiHostMsg_ResourceSyncCall::WriteReplyParams(context.sync_reply_msg,
90 context.params, msg);
91 Send(context.sync_reply_msg);
92 } else {
93 if (context.routing_id != MSG_ROUTING_NONE) {
94 Send(new PpapiHostMsg_InProcessResourceReply(context.routing_id,
95 context.params,
96 msg));
97 } else {
98 Send(new PpapiPluginMsg_ResourceReply(context.params, msg));
103 void PpapiHost::SendUnsolicitedReply(PP_Resource resource,
104 const IPC::Message& msg) {
105 SendUnsolicitedReplyWithHandles(
106 resource, msg, std::vector<SerializedHandle>());
109 void PpapiHost::SendUnsolicitedReplyWithHandles(
110 PP_Resource resource,
111 const IPC::Message& msg,
112 const std::vector<SerializedHandle>& handles) {
113 TRACE_EVENT2("ppapi proxy", "PpapiHost::SendUnsolicitedReplyWithHandles",
114 "Class", IPC_MESSAGE_ID_CLASS(msg.type()),
115 "Line", IPC_MESSAGE_ID_LINE(msg.type()));
116 DCHECK(resource); // If this fails, host is probably pending.
117 proxy::ResourceMessageReplyParams params(resource, 0);
118 for (std::vector<SerializedHandle>::const_iterator it = handles.begin();
119 it != handles.end(); ++it) {
120 params.AppendHandle(*it);
122 Send(new PpapiPluginMsg_ResourceReply(params, msg));
125 scoped_ptr<ResourceHost> PpapiHost::CreateResourceHost(
126 PP_Resource resource,
127 PP_Instance instance,
128 const IPC::Message& nested_msg) {
129 scoped_ptr<ResourceHost> resource_host;
130 DCHECK(!host_factory_filters_.empty()); // Caller forgot to add a factory.
131 for (size_t i = 0; i < host_factory_filters_.size(); i++) {
132 resource_host =
133 host_factory_filters_[i]
134 ->CreateResourceHost(this, resource, instance, nested_msg)
135 .Pass();
136 if (resource_host.get())
137 break;
139 return resource_host.Pass();
142 int PpapiHost::AddPendingResourceHost(scoped_ptr<ResourceHost> resource_host) {
143 // The resource ID should not be assigned.
144 if (!resource_host.get() || resource_host->pp_resource() != 0) {
145 NOTREACHED();
146 return 0;
149 if (pending_resource_hosts_.size() + resources_.size()
150 >= kMaxResourcesPerPlugin) {
151 return 0;
154 int pending_id = next_pending_resource_host_id_++;
155 pending_resource_hosts_[pending_id] =
156 linked_ptr<ResourceHost>(resource_host.release());
157 return pending_id;
160 void PpapiHost::AddHostFactoryFilter(scoped_ptr<HostFactory> filter) {
161 host_factory_filters_.push_back(filter.release());
164 void PpapiHost::AddInstanceMessageFilter(
165 scoped_ptr<InstanceMessageFilter> filter) {
166 instance_message_filters_.push_back(filter.release());
169 void PpapiHost::OnHostMsgResourceCall(
170 const proxy::ResourceMessageCallParams& params,
171 const IPC::Message& nested_msg) {
172 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceCall",
173 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
174 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
175 HostMessageContext context(params);
176 HandleResourceCall(params, nested_msg, &context);
179 void PpapiHost::OnHostMsgInProcessResourceCall(
180 int routing_id,
181 const proxy::ResourceMessageCallParams& params,
182 const IPC::Message& nested_msg) {
183 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgInProcessResourceCall",
184 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
185 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
186 HostMessageContext context(routing_id, params);
187 HandleResourceCall(params, nested_msg, &context);
190 void PpapiHost::OnHostMsgResourceSyncCall(
191 const proxy::ResourceMessageCallParams& params,
192 const IPC::Message& nested_msg,
193 IPC::Message* reply_msg) {
194 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceSyncCall",
195 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
196 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
197 // Sync messages should always have callback set because they always expect
198 // a reply from the host.
199 DCHECK(params.has_callback());
200 // Stash the |reply_msg| in the context so that it can be used to reply
201 // to the sync message.
202 HostMessageContext context(params, reply_msg);
203 HandleResourceCall(params, nested_msg, &context);
206 void PpapiHost::HandleResourceCall(
207 const proxy::ResourceMessageCallParams& params,
208 const IPC::Message& nested_msg,
209 HostMessageContext* context) {
210 ResourceHost* resource_host = GetResourceHost(params.pp_resource());
211 if (resource_host) {
212 // CAUTION: Handling the message may cause the destruction of this object.
213 resource_host->HandleMessage(nested_msg, context);
214 } else {
215 if (context->params.has_callback()) {
216 ReplyMessageContext reply_context = context->MakeReplyMessageContext();
217 reply_context.params.set_result(PP_ERROR_BADRESOURCE);
218 SendReply(reply_context, context->reply_msg);
223 void PpapiHost::OnHostMsgResourceCreated(
224 const proxy::ResourceMessageCallParams& params,
225 PP_Instance instance,
226 const IPC::Message& nested_msg) {
227 TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceCreated",
228 "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
229 "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
231 if (pending_resource_hosts_.size() + resources_.size()
232 >= kMaxResourcesPerPlugin) {
233 return;
236 // Run through all filters until one grabs this message.
237 scoped_ptr<ResourceHost> resource_host =
238 CreateResourceHost(params.pp_resource(), instance, nested_msg);
240 if (!resource_host.get()) {
241 NOTREACHED();
242 return;
245 // Resource should have been assigned a nonzero PP_Resource.
246 DCHECK(resource_host->pp_resource());
248 resources_[params.pp_resource()] =
249 linked_ptr<ResourceHost>(resource_host.release());
252 void PpapiHost::OnHostMsgAttachToPendingHost(PP_Resource pp_resource,
253 int pending_host_id) {
254 PendingHostResourceMap::iterator found =
255 pending_resource_hosts_.find(pending_host_id);
256 if (found == pending_resource_hosts_.end()) {
257 // Plugin sent a bad ID.
258 NOTREACHED();
259 return;
261 found->second->SetPPResourceForPendingHost(pp_resource);
262 resources_[pp_resource] = found->second;
263 pending_resource_hosts_.erase(found);
266 void PpapiHost::OnHostMsgResourceDestroyed(PP_Resource resource) {
267 ResourceMap::iterator found = resources_.find(resource);
268 if (found == resources_.end()) {
269 NOTREACHED();
270 return;
272 // Invoking the HostResource destructor might result in looking up the
273 // PP_Resource in resources_. std::map is not well specified as to whether the
274 // element will be there or not. Therefore, we delay destruction of the
275 // HostResource until after we've made sure the map no longer contains
276 // |resource|.
277 linked_ptr<ResourceHost> delete_at_end_of_scope(found->second);
278 resources_.erase(found);
281 ResourceHost* PpapiHost::GetResourceHost(PP_Resource resource) const {
282 ResourceMap::const_iterator found = resources_.find(resource);
283 return found == resources_.end() ? NULL : found->second.get();
286 } // namespace host
287 } // namespace ppapi