• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/host/ppapi_host.h"
6 
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"
17 
18 namespace ppapi {
19 namespace host {
20 
21 using proxy::SerializedHandle;
22 
23 namespace {
24 
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;
28 
29 }  // namespace
30 
PpapiHost(IPC::Sender * sender,const PpapiPermissions & perms)31 PpapiHost::PpapiHost(IPC::Sender* sender,
32                      const PpapiPermissions& perms)
33     : sender_(sender),
34       permissions_(perms),
35       next_pending_resource_host_id_(1) {
36 }
37 
~PpapiHost()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();
43 
44   // The resources may also want to use us in their destructors.
45   resources_.clear();
46   pending_resource_hosts_.clear();
47 }
48 
Send(IPC::Message * msg)49 bool PpapiHost::Send(IPC::Message* msg) {
50   return sender_->Send(msg);
51 }
52 
OnMessageReceived(const IPC::Message & 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()
70 
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;
76       }
77     }
78   }
79 
80   return handled;
81 }
82 
SendReply(const ReplyMessageContext & context,const IPC::Message & msg)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));
99     }
100   }
101 }
102 
SendUnsolicitedReply(PP_Resource resource,const IPC::Message & msg)103 void PpapiHost::SendUnsolicitedReply(PP_Resource resource,
104                                      const IPC::Message& msg) {
105   SendUnsolicitedReplyWithHandles(
106       resource, msg, std::vector<SerializedHandle>());
107 }
108 
SendUnsolicitedReplyWithHandles(PP_Resource resource,const IPC::Message & msg,const std::vector<SerializedHandle> & handles)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);
121   }
122   Send(new PpapiPluginMsg_ResourceReply(params, msg));
123 }
124 
CreateResourceHost(const proxy::ResourceMessageCallParams & params,PP_Instance instance,const IPC::Message & nested_msg)125 scoped_ptr<ResourceHost> PpapiHost::CreateResourceHost(
126     const proxy::ResourceMessageCallParams& params,
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 = host_factory_filters_[i]->CreateResourceHost(
133         this, params, instance, nested_msg).Pass();
134     if (resource_host.get())
135       break;
136   }
137   return resource_host.Pass();
138 }
139 
AddPendingResourceHost(scoped_ptr<ResourceHost> resource_host)140 int PpapiHost::AddPendingResourceHost(scoped_ptr<ResourceHost> resource_host) {
141   // The resource ID should not be assigned.
142   if (!resource_host.get() || resource_host->pp_resource() != 0) {
143     NOTREACHED();
144     return 0;
145   }
146 
147   if (pending_resource_hosts_.size() + resources_.size()
148       >= kMaxResourcesPerPlugin) {
149     return 0;
150   }
151 
152   int pending_id = next_pending_resource_host_id_++;
153   pending_resource_hosts_[pending_id] =
154       linked_ptr<ResourceHost>(resource_host.release());
155   return pending_id;
156 }
157 
AddHostFactoryFilter(scoped_ptr<HostFactory> filter)158 void PpapiHost::AddHostFactoryFilter(scoped_ptr<HostFactory> filter) {
159   host_factory_filters_.push_back(filter.release());
160 }
161 
AddInstanceMessageFilter(scoped_ptr<InstanceMessageFilter> filter)162 void PpapiHost::AddInstanceMessageFilter(
163     scoped_ptr<InstanceMessageFilter> filter) {
164   instance_message_filters_.push_back(filter.release());
165 }
166 
OnHostMsgResourceCall(const proxy::ResourceMessageCallParams & params,const IPC::Message & nested_msg)167 void PpapiHost::OnHostMsgResourceCall(
168     const proxy::ResourceMessageCallParams& params,
169     const IPC::Message& nested_msg) {
170   TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceCall",
171                "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
172                "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
173   HostMessageContext context(params);
174   HandleResourceCall(params, nested_msg, &context);
175 }
176 
OnHostMsgInProcessResourceCall(int routing_id,const proxy::ResourceMessageCallParams & params,const IPC::Message & nested_msg)177 void PpapiHost::OnHostMsgInProcessResourceCall(
178     int routing_id,
179     const proxy::ResourceMessageCallParams& params,
180     const IPC::Message& nested_msg) {
181   TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgInProcessResourceCall",
182                "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
183                "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
184   HostMessageContext context(routing_id, params);
185   HandleResourceCall(params, nested_msg, &context);
186 }
187 
OnHostMsgResourceSyncCall(const proxy::ResourceMessageCallParams & params,const IPC::Message & nested_msg,IPC::Message * reply_msg)188 void PpapiHost::OnHostMsgResourceSyncCall(
189     const proxy::ResourceMessageCallParams& params,
190     const IPC::Message& nested_msg,
191     IPC::Message* reply_msg) {
192   TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceSyncCall",
193                "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
194                "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
195   // Sync messages should always have callback set because they always expect
196   // a reply from the host.
197   DCHECK(params.has_callback());
198   // Stash the |reply_msg| in the context so that it can be used to reply
199   // to the sync message.
200   HostMessageContext context(params, reply_msg);
201   HandleResourceCall(params, nested_msg, &context);
202 }
203 
HandleResourceCall(const proxy::ResourceMessageCallParams & params,const IPC::Message & nested_msg,HostMessageContext * context)204 void PpapiHost::HandleResourceCall(
205     const proxy::ResourceMessageCallParams& params,
206     const IPC::Message& nested_msg,
207     HostMessageContext* context) {
208   ResourceHost* resource_host = GetResourceHost(params.pp_resource());
209   if (resource_host) {
210     // CAUTION: Handling the message may cause the destruction of this object.
211     resource_host->HandleMessage(nested_msg, context);
212   } else {
213     if (context->params.has_callback()) {
214       ReplyMessageContext reply_context = context->MakeReplyMessageContext();
215       reply_context.params.set_result(PP_ERROR_BADRESOURCE);
216       SendReply(reply_context, context->reply_msg);
217     }
218   }
219 }
220 
OnHostMsgResourceCreated(const proxy::ResourceMessageCallParams & params,PP_Instance instance,const IPC::Message & nested_msg)221 void PpapiHost::OnHostMsgResourceCreated(
222     const proxy::ResourceMessageCallParams& params,
223     PP_Instance instance,
224     const IPC::Message& nested_msg) {
225   TRACE_EVENT2("ppapi proxy", "PpapiHost::OnHostMsgResourceCreated",
226                "Class", IPC_MESSAGE_ID_CLASS(nested_msg.type()),
227                "Line", IPC_MESSAGE_ID_LINE(nested_msg.type()));
228 
229   if (pending_resource_hosts_.size() + resources_.size()
230       >= kMaxResourcesPerPlugin) {
231     return;
232   }
233 
234   // Run through all filters until one grabs this message.
235   scoped_ptr<ResourceHost> resource_host = CreateResourceHost(params, instance,
236                                                               nested_msg);
237 
238   if (!resource_host.get()) {
239     NOTREACHED();
240     return;
241   }
242 
243   // Resource should have been assigned a nonzero PP_Resource.
244   DCHECK(resource_host->pp_resource());
245 
246   resources_[params.pp_resource()] =
247       linked_ptr<ResourceHost>(resource_host.release());
248 }
249 
OnHostMsgAttachToPendingHost(PP_Resource pp_resource,int pending_host_id)250 void PpapiHost::OnHostMsgAttachToPendingHost(PP_Resource pp_resource,
251                                              int pending_host_id) {
252   PendingHostResourceMap::iterator found =
253       pending_resource_hosts_.find(pending_host_id);
254   if (found == pending_resource_hosts_.end()) {
255     // Plugin sent a bad ID.
256     NOTREACHED();
257     return;
258   }
259   found->second->SetPPResourceForPendingHost(pp_resource);
260   resources_[pp_resource] = found->second;
261   pending_resource_hosts_.erase(found);
262 }
263 
OnHostMsgResourceDestroyed(PP_Resource resource)264 void PpapiHost::OnHostMsgResourceDestroyed(PP_Resource resource) {
265   ResourceMap::iterator found = resources_.find(resource);
266   if (found == resources_.end()) {
267     NOTREACHED();
268     return;
269   }
270   // Invoking the HostResource destructor might result in looking up the
271   // PP_Resource in resources_. std::map is not well specified as to whether the
272   // element will be there or not. Therefore, we delay destruction of the
273   // HostResource until after we've made sure the map no longer contains
274   // |resource|.
275   linked_ptr<ResourceHost> delete_at_end_of_scope(found->second);
276   resources_.erase(found);
277 }
278 
GetResourceHost(PP_Resource resource) const279 ResourceHost* PpapiHost::GetResourceHost(PP_Resource resource) const {
280   ResourceMap::const_iterator found = resources_.find(resource);
281   return found == resources_.end() ? NULL : found->second.get();
282 }
283 
284 }  // namespace host
285 }  // namespace ppapi
286