1// Copyright (c) 2011 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 "chrome/browser/renderer_host/chrome_render_message_filter.h"
6
7#include "base/file_path.h"
8#include "base/metrics/histogram.h"
9#include "chrome/browser/browser_process.h"
10#include "chrome/browser/extensions/extension_message_service.h"
11#include "chrome/browser/metrics/histogram_synchronizer.h"
12#include "chrome/browser/nacl_host/nacl_process_host.h"
13#include "chrome/browser/net/chrome_url_request_context.h"
14#include "chrome/browser/net/predictor_api.h"
15#include "chrome/browser/prefs/pref_member.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/task_manager/task_manager.h"
18#include "chrome/common/extensions/extension_file_util.h"
19#include "chrome/common/extensions/extension_message_bundle.h"
20#include "chrome/common/extensions/extension_messages.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/common/render_messages.h"
23#include "content/browser/renderer_host/resource_dispatcher_host.h"
24
25#if defined(USE_TCMALLOC)
26#include "chrome/browser/browser_about_handler.h"
27#endif
28
29using WebKit::WebCache;
30
31ChromeRenderMessageFilter::ChromeRenderMessageFilter(
32    int render_process_id,
33    Profile* profile,
34    net::URLRequestContextGetter* request_context)
35    : render_process_id_(render_process_id),
36      profile_(profile),
37      request_context_(request_context) {
38  allow_outdated_plugins_.Init(prefs::kPluginsAllowOutdated,
39                               profile_->GetPrefs(), NULL);
40  allow_outdated_plugins_.MoveToThread(BrowserThread::IO);
41}
42
43ChromeRenderMessageFilter::~ChromeRenderMessageFilter() {
44}
45
46bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message,
47                                                  bool* message_was_ok) {
48  bool handled = true;
49  IPC_BEGIN_MESSAGE_MAP_EX(ChromeRenderMessageFilter, message, *message_was_ok)
50    IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_LaunchNaCl, OnLaunchNaCl)
51    IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch)
52    IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms, OnRendererHistograms)
53    IPC_MESSAGE_HANDLER(ViewHostMsg_ResourceTypeStats, OnResourceTypeStats)
54    IPC_MESSAGE_HANDLER(ViewHostMsg_V8HeapStats, OnV8HeapStats)
55    IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToExtension,
56                        OnOpenChannelToExtension)
57    IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab)
58    IPC_MESSAGE_HANDLER_DELAY_REPLY(ExtensionHostMsg_GetMessageBundle,
59                                    OnGetExtensionMessageBundle)
60#if defined(USE_TCMALLOC)
61    IPC_MESSAGE_HANDLER(ViewHostMsg_RendererTcmalloc, OnRendererTcmalloc)
62#endif
63    IPC_MESSAGE_HANDLER(ViewHostMsg_GetOutdatedPluginsPolicy,
64                        OnGetOutdatedPluginsPolicy)
65    IPC_MESSAGE_UNHANDLED(handled = false)
66  IPC_END_MESSAGE_MAP()
67
68  return handled;
69}
70
71void ChromeRenderMessageFilter::OnDestruct() const {
72  // Destroy on the UI thread because we contain a PrefMember.
73  BrowserThread::DeleteOnUIThread::Destruct(this);
74}
75
76void ChromeRenderMessageFilter::OverrideThreadForMessage(
77    const IPC::Message& message, BrowserThread::ID* thread) {
78  if (message.type() == ViewHostMsg_ResourceTypeStats::ID ||
79#if defined(USE_TCMALLOC)
80      message.type() == ViewHostMsg_RendererTcmalloc::ID ||
81#endif
82      message.type() == ViewHostMsg_ResourceTypeStats::ID) {
83    *thread = BrowserThread::UI;
84  }
85}
86
87void ChromeRenderMessageFilter::OnLaunchNaCl(
88    const std::wstring& url, int channel_descriptor, IPC::Message* reply_msg) {
89  NaClProcessHost* host = new NaClProcessHost(url);
90  host->Launch(this, channel_descriptor, reply_msg);
91}
92
93void ChromeRenderMessageFilter::OnDnsPrefetch(
94    const std::vector<std::string>& hostnames) {
95  chrome_browser_net::DnsPrefetchList(hostnames);
96}
97
98void ChromeRenderMessageFilter::OnRendererHistograms(
99    int sequence_number,
100    const std::vector<std::string>& histograms) {
101  HistogramSynchronizer::DeserializeHistogramList(sequence_number, histograms);
102}
103
104void ChromeRenderMessageFilter::OnResourceTypeStats(
105    const WebCache::ResourceTypeStats& stats) {
106  HISTOGRAM_COUNTS("WebCoreCache.ImagesSizeKB",
107                   static_cast<int>(stats.images.size / 1024));
108  HISTOGRAM_COUNTS("WebCoreCache.CSSStylesheetsSizeKB",
109                   static_cast<int>(stats.cssStyleSheets.size / 1024));
110  HISTOGRAM_COUNTS("WebCoreCache.ScriptsSizeKB",
111                   static_cast<int>(stats.scripts.size / 1024));
112  HISTOGRAM_COUNTS("WebCoreCache.XSLStylesheetsSizeKB",
113                   static_cast<int>(stats.xslStyleSheets.size / 1024));
114  HISTOGRAM_COUNTS("WebCoreCache.FontsSizeKB",
115                   static_cast<int>(stats.fonts.size / 1024));
116
117  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118  TaskManager::GetInstance()->model()->NotifyResourceTypeStats(
119      base::GetProcId(peer_handle()), stats);
120}
121
122void ChromeRenderMessageFilter::OnV8HeapStats(int v8_memory_allocated,
123                                        int v8_memory_used) {
124  TaskManager::GetInstance()->model()->NotifyV8HeapStats(
125      base::GetProcId(peer_handle()),
126      static_cast<size_t>(v8_memory_allocated),
127      static_cast<size_t>(v8_memory_used));
128}
129
130void ChromeRenderMessageFilter::OnOpenChannelToExtension(
131    int routing_id, const std::string& source_extension_id,
132    const std::string& target_extension_id,
133    const std::string& channel_name, int* port_id) {
134  int port2_id;
135  ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
136
137  BrowserThread::PostTask(
138      BrowserThread::UI, FROM_HERE,
139      NewRunnableMethod(
140          this, &ChromeRenderMessageFilter::OpenChannelToExtensionOnUIThread,
141          render_process_id_, routing_id, port2_id, source_extension_id,
142          target_extension_id, channel_name));
143}
144
145void ChromeRenderMessageFilter::OpenChannelToExtensionOnUIThread(
146    int source_process_id, int source_routing_id,
147    int receiver_port_id,
148    const std::string& source_extension_id,
149    const std::string& target_extension_id,
150    const std::string& channel_name) {
151  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152  profile_->GetExtensionMessageService()->OpenChannelToExtension(
153      source_process_id, source_routing_id, receiver_port_id,
154      source_extension_id, target_extension_id, channel_name);
155}
156
157void ChromeRenderMessageFilter::OnOpenChannelToTab(
158    int routing_id, int tab_id, const std::string& extension_id,
159    const std::string& channel_name, int* port_id) {
160  int port2_id;
161  ExtensionMessageService::AllocatePortIdPair(port_id, &port2_id);
162
163  BrowserThread::PostTask(
164      BrowserThread::UI, FROM_HERE,
165      NewRunnableMethod(
166          this, &ChromeRenderMessageFilter::OpenChannelToTabOnUIThread,
167          render_process_id_, routing_id, port2_id, tab_id, extension_id,
168          channel_name));
169}
170
171void ChromeRenderMessageFilter::OpenChannelToTabOnUIThread(
172    int source_process_id, int source_routing_id,
173    int receiver_port_id,
174    int tab_id,
175    const std::string& extension_id,
176    const std::string& channel_name) {
177  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
178  profile_->GetExtensionMessageService()->OpenChannelToTab(
179      source_process_id, source_routing_id, receiver_port_id,
180      tab_id, extension_id, channel_name);
181}
182
183void ChromeRenderMessageFilter::OnGetExtensionMessageBundle(
184    const std::string& extension_id, IPC::Message* reply_msg) {
185  ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>(
186    request_context_->GetURLRequestContext());
187
188  FilePath extension_path =
189      context->extension_info_map()->GetPathForExtension(extension_id);
190  std::string default_locale =
191      context->extension_info_map()->GetDefaultLocaleForExtension(extension_id);
192
193  BrowserThread::PostTask(
194      BrowserThread::FILE, FROM_HERE,
195      NewRunnableMethod(
196          this,
197          &ChromeRenderMessageFilter::OnGetExtensionMessageBundleOnFileThread,
198          extension_path, extension_id, default_locale, reply_msg));
199}
200
201void ChromeRenderMessageFilter::OnGetExtensionMessageBundleOnFileThread(
202    const FilePath& extension_path,
203    const std::string& extension_id,
204    const std::string& default_locale,
205    IPC::Message* reply_msg) {
206  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
207
208  std::map<std::string, std::string> dictionary_map;
209  if (!default_locale.empty()) {
210    // Touch disk only if extension is localized.
211    std::string error;
212    scoped_ptr<ExtensionMessageBundle> bundle(
213        extension_file_util::LoadExtensionMessageBundle(
214            extension_path, default_locale, &error));
215
216    if (bundle.get())
217      dictionary_map = *bundle->dictionary();
218  }
219
220  // Add @@extension_id reserved message here, so it's available to
221  // non-localized extensions too.
222  dictionary_map.insert(
223      std::make_pair(ExtensionMessageBundle::kExtensionIdKey, extension_id));
224
225  ExtensionHostMsg_GetMessageBundle::WriteReplyParams(
226      reply_msg, dictionary_map);
227  Send(reply_msg);
228}
229
230#if defined(USE_TCMALLOC)
231void ChromeRenderMessageFilter::OnRendererTcmalloc(base::ProcessId pid,
232                                                   const std::string& output) {
233  AboutTcmallocRendererCallback(pid, output);
234}
235#endif
236
237void ChromeRenderMessageFilter::OnGetOutdatedPluginsPolicy(
238    ContentSetting* policy) {
239  *policy = CONTENT_SETTING_ALLOW;
240  if (!allow_outdated_plugins_.GetValue()) {
241    // If this is false by policy, the plugin is blocked; otherwise, it is
242    // blocked initially but the user can load it manually.
243    *policy = allow_outdated_plugins_.IsManaged() ?
244        CONTENT_SETTING_BLOCK : CONTENT_SETTING_ASK;
245  }
246}
247