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 "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
6
7 #include "base/metrics/sparse_histogram.h"
8 #include "content/browser/renderer_host/pepper/pepper_message_filter.h"
9 #include "content/browser/tracing/trace_message_filter.h"
10 #include "content/common/pepper_renderer_instance_data.h"
11 #include "content/public/common/process_type.h"
12 #include "ipc/ipc_message_macros.h"
13 #include "ppapi/proxy/ppapi_messages.h"
14
15 namespace content {
16
17 // static
CreateExternalPluginProcess(IPC::Sender * sender,ppapi::PpapiPermissions permissions,base::ProcessHandle plugin_child_process,IPC::ChannelProxy * channel,int render_process_id,int render_view_id,const base::FilePath & profile_directory)18 BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess(
19 IPC::Sender* sender,
20 ppapi::PpapiPermissions permissions,
21 base::ProcessHandle plugin_child_process,
22 IPC::ChannelProxy* channel,
23 int render_process_id,
24 int render_view_id,
25 const base::FilePath& profile_directory) {
26 // The plugin name and path shouldn't be needed for external plugins.
27 BrowserPpapiHostImpl* browser_ppapi_host =
28 new BrowserPpapiHostImpl(sender,
29 permissions,
30 std::string(),
31 base::FilePath(),
32 profile_directory,
33 false /* in_process */,
34 true /* external_plugin */);
35 browser_ppapi_host->set_plugin_process_handle(plugin_child_process);
36
37 scoped_refptr<PepperMessageFilter> pepper_message_filter(
38 new PepperMessageFilter());
39 channel->AddFilter(pepper_message_filter->GetFilter());
40 channel->AddFilter(browser_ppapi_host->message_filter().get());
41 channel->AddFilter((new TraceMessageFilter())->GetFilter());
42
43 return browser_ppapi_host;
44 }
45
BrowserPpapiHostImpl(IPC::Sender * sender,const ppapi::PpapiPermissions & permissions,const std::string & plugin_name,const base::FilePath & plugin_path,const base::FilePath & profile_data_directory,bool in_process,bool external_plugin)46 BrowserPpapiHostImpl::BrowserPpapiHostImpl(
47 IPC::Sender* sender,
48 const ppapi::PpapiPermissions& permissions,
49 const std::string& plugin_name,
50 const base::FilePath& plugin_path,
51 const base::FilePath& profile_data_directory,
52 bool in_process,
53 bool external_plugin)
54 : ppapi_host_(new ppapi::host::PpapiHost(sender, permissions)),
55 plugin_process_handle_(base::kNullProcessHandle),
56 plugin_name_(plugin_name),
57 plugin_path_(plugin_path),
58 profile_data_directory_(profile_data_directory),
59 in_process_(in_process),
60 external_plugin_(external_plugin),
61 ssl_context_helper_(new SSLContextHelper()) {
62 message_filter_ = new HostMessageFilter(ppapi_host_.get(), this);
63 ppapi_host_->AddHostFactoryFilter(scoped_ptr<ppapi::host::HostFactory>(
64 new ContentBrowserPepperHostFactory(this)));
65 }
66
~BrowserPpapiHostImpl()67 BrowserPpapiHostImpl::~BrowserPpapiHostImpl() {
68 // Notify the filter so it won't foward messages to us.
69 message_filter_->OnHostDestroyed();
70
71 // Delete the host explicitly first. This shutdown will destroy the
72 // resources, which may want to do cleanup in their destructors and expect
73 // their pointers to us to be valid.
74 ppapi_host_.reset();
75 }
76
GetPpapiHost()77 ppapi::host::PpapiHost* BrowserPpapiHostImpl::GetPpapiHost() {
78 return ppapi_host_.get();
79 }
80
GetPluginProcessHandle() const81 base::ProcessHandle BrowserPpapiHostImpl::GetPluginProcessHandle() const {
82 // Handle should previously have been set before use.
83 DCHECK(in_process_ || plugin_process_handle_ != base::kNullProcessHandle);
84 return plugin_process_handle_;
85 }
86
IsValidInstance(PP_Instance instance) const87 bool BrowserPpapiHostImpl::IsValidInstance(PP_Instance instance) const {
88 return instance_map_.find(instance) != instance_map_.end();
89 }
90
GetRenderFrameIDsForInstance(PP_Instance instance,int * render_process_id,int * render_frame_id) const91 bool BrowserPpapiHostImpl::GetRenderFrameIDsForInstance(
92 PP_Instance instance,
93 int* render_process_id,
94 int* render_frame_id) const {
95 InstanceMap::const_iterator found = instance_map_.find(instance);
96 if (found == instance_map_.end()) {
97 *render_process_id = 0;
98 *render_frame_id = 0;
99 return false;
100 }
101
102 *render_process_id = found->second.render_process_id;
103 *render_frame_id = found->second.render_frame_id;
104 return true;
105 }
106
GetPluginName()107 const std::string& BrowserPpapiHostImpl::GetPluginName() {
108 return plugin_name_;
109 }
110
GetPluginPath()111 const base::FilePath& BrowserPpapiHostImpl::GetPluginPath() {
112 return plugin_path_;
113 }
114
GetProfileDataDirectory()115 const base::FilePath& BrowserPpapiHostImpl::GetProfileDataDirectory() {
116 return profile_data_directory_;
117 }
118
GetDocumentURLForInstance(PP_Instance instance)119 GURL BrowserPpapiHostImpl::GetDocumentURLForInstance(PP_Instance instance) {
120 InstanceMap::const_iterator found = instance_map_.find(instance);
121 if (found == instance_map_.end())
122 return GURL();
123 return found->second.document_url;
124 }
125
GetPluginURLForInstance(PP_Instance instance)126 GURL BrowserPpapiHostImpl::GetPluginURLForInstance(PP_Instance instance) {
127 InstanceMap::const_iterator found = instance_map_.find(instance);
128 if (found == instance_map_.end())
129 return GURL();
130 return found->second.plugin_url;
131 }
132
SetOnKeepaliveCallback(const BrowserPpapiHost::OnKeepaliveCallback & callback)133 void BrowserPpapiHostImpl::SetOnKeepaliveCallback(
134 const BrowserPpapiHost::OnKeepaliveCallback& callback) {
135 on_keepalive_callback_ = callback;
136 }
137
AddInstance(PP_Instance instance,const PepperRendererInstanceData & instance_data)138 void BrowserPpapiHostImpl::AddInstance(
139 PP_Instance instance,
140 const PepperRendererInstanceData& instance_data) {
141 DCHECK(instance_map_.find(instance) == instance_map_.end());
142 instance_map_[instance] = instance_data;
143 }
144
DeleteInstance(PP_Instance instance)145 void BrowserPpapiHostImpl::DeleteInstance(PP_Instance instance) {
146 InstanceMap::iterator found = instance_map_.find(instance);
147 if (found == instance_map_.end()) {
148 NOTREACHED();
149 return;
150 }
151 instance_map_.erase(found);
152 }
153
HostMessageFilter(ppapi::host::PpapiHost * ppapi_host,BrowserPpapiHostImpl * browser_ppapi_host_impl)154 BrowserPpapiHostImpl::HostMessageFilter::HostMessageFilter(
155 ppapi::host::PpapiHost* ppapi_host,
156 BrowserPpapiHostImpl* browser_ppapi_host_impl)
157 : ppapi_host_(ppapi_host),
158 browser_ppapi_host_impl_(browser_ppapi_host_impl) {}
159
OnMessageReceived(const IPC::Message & msg)160 bool BrowserPpapiHostImpl::HostMessageFilter::OnMessageReceived(
161 const IPC::Message& msg) {
162 // Don't forward messages if our owner object has been destroyed.
163 if (!ppapi_host_)
164 return false;
165
166 bool handled = true;
167 IPC_BEGIN_MESSAGE_MAP(BrowserPpapiHostImpl::HostMessageFilter, msg)
168 // Add necessary message handlers here.
169 IPC_MESSAGE_HANDLER(PpapiHostMsg_Keepalive, OnKeepalive)
170 IPC_MESSAGE_HANDLER(PpapiHostMsg_LogInterfaceUsage,
171 OnHostMsgLogInterfaceUsage)
172 IPC_MESSAGE_UNHANDLED(handled = ppapi_host_->OnMessageReceived(msg))
173 IPC_END_MESSAGE_MAP();
174 return handled;
175 }
176
OnHostDestroyed()177 void BrowserPpapiHostImpl::HostMessageFilter::OnHostDestroyed() {
178 DCHECK(ppapi_host_);
179 ppapi_host_ = NULL;
180 browser_ppapi_host_impl_ = NULL;
181 }
182
~HostMessageFilter()183 BrowserPpapiHostImpl::HostMessageFilter::~HostMessageFilter() {}
184
OnKeepalive()185 void BrowserPpapiHostImpl::HostMessageFilter::OnKeepalive() {
186 if (browser_ppapi_host_impl_)
187 browser_ppapi_host_impl_->OnKeepalive();
188 }
189
OnHostMsgLogInterfaceUsage(int hash) const190 void BrowserPpapiHostImpl::HostMessageFilter::OnHostMsgLogInterfaceUsage(
191 int hash) const {
192 UMA_HISTOGRAM_SPARSE_SLOWLY("Pepper.InterfaceUsed", hash);
193 }
194
OnKeepalive()195 void BrowserPpapiHostImpl::OnKeepalive() {
196 // An instance has been active. The on_keepalive_callback_ will be
197 // used to permit the content embedder to handle this, e.g. by tracking
198 // activity and shutting down processes that go idle.
199 //
200 // Currently embedders do not need to distinguish between instances having
201 // different idle state, and thus this implementation handles all instances
202 // for this module together.
203
204 if (on_keepalive_callback_.is_null())
205 return;
206
207 BrowserPpapiHost::OnKeepaliveInstanceData instance_data(instance_map_.size());
208
209 InstanceMap::iterator instance = instance_map_.begin();
210 int i = 0;
211 while (instance != instance_map_.end()) {
212 instance_data[i].render_process_id = instance->second.render_process_id;
213 instance_data[i].render_frame_id = instance->second.render_frame_id;
214 instance_data[i].document_url = instance->second.document_url;
215 ++instance;
216 ++i;
217 }
218 on_keepalive_callback_.Run(instance_data, profile_data_directory_);
219 }
220
221 } // namespace content
222