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
15namespace content {
16
17// static
18BrowserPpapiHost* 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
46BrowserPpapiHostImpl::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
67BrowserPpapiHostImpl::~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
77ppapi::host::PpapiHost* BrowserPpapiHostImpl::GetPpapiHost() {
78  return ppapi_host_.get();
79}
80
81base::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
87bool BrowserPpapiHostImpl::IsValidInstance(PP_Instance instance) const {
88  return instance_map_.find(instance) != instance_map_.end();
89}
90
91bool 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
107const std::string& BrowserPpapiHostImpl::GetPluginName() {
108  return plugin_name_;
109}
110
111const base::FilePath& BrowserPpapiHostImpl::GetPluginPath() {
112  return plugin_path_;
113}
114
115const base::FilePath& BrowserPpapiHostImpl::GetProfileDataDirectory() {
116  return profile_data_directory_;
117}
118
119GURL 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
126GURL 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
133void BrowserPpapiHostImpl::SetOnKeepaliveCallback(
134    const BrowserPpapiHost::OnKeepaliveCallback& callback) {
135  on_keepalive_callback_ = callback;
136}
137
138void 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
145void 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
154BrowserPpapiHostImpl::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
160bool 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
177void BrowserPpapiHostImpl::HostMessageFilter::OnHostDestroyed() {
178  DCHECK(ppapi_host_);
179  ppapi_host_ = NULL;
180  browser_ppapi_host_impl_ = NULL;
181}
182
183BrowserPpapiHostImpl::HostMessageFilter::~HostMessageFilter() {}
184
185void BrowserPpapiHostImpl::HostMessageFilter::OnKeepalive() {
186  if (browser_ppapi_host_impl_)
187    browser_ppapi_host_impl_->OnKeepalive();
188}
189
190void BrowserPpapiHostImpl::HostMessageFilter::OnHostMsgLogInterfaceUsage(
191    int hash) const {
192  UMA_HISTOGRAM_SPARSE_SLOWLY("Pepper.InterfaceUsed", hash);
193}
194
195void 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