chrome_render_message_filter.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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 "chrome/browser/renderer_host/chrome_render_message_filter.h" 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/metrics/histogram.h" 12#include "base/strings/utf_string_conversions.h" 13#include "chrome/browser/browser_process.h" 14#include "chrome/browser/chrome_notification_types.h" 15#include "chrome/browser/content_settings/cookie_settings.h" 16#include "chrome/browser/content_settings/tab_specific_content_settings.h" 17#include "chrome/browser/extensions/activity_log/activity_action_constants.h" 18#include "chrome/browser/extensions/activity_log/activity_actions.h" 19#include "chrome/browser/extensions/activity_log/activity_log.h" 20#include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h" 21#include "chrome/browser/extensions/api/messaging/message_service.h" 22#include "chrome/browser/metrics/metrics_service.h" 23#include "chrome/browser/net/chrome_url_request_context.h" 24#include "chrome/browser/net/predictor.h" 25#include "chrome/browser/profiles/profile_manager.h" 26#include "chrome/browser/task_manager/task_manager.h" 27#include "chrome/common/extensions/api/i18n/default_locale_handler.h" 28#include "chrome/common/extensions/extension_file_util.h" 29#include "chrome/common/extensions/message_bundle.h" 30#include "chrome/common/render_messages.h" 31#include "content/public/browser/notification_service.h" 32#include "content/public/browser/render_process_host.h" 33#include "extensions/browser/extension_system.h" 34#include "extensions/common/constants.h" 35#include "extensions/common/extension_messages.h" 36 37#if defined(USE_TCMALLOC) 38#include "chrome/browser/browser_about_handler.h" 39#endif 40 41using content::BrowserThread; 42using extensions::APIPermission; 43using blink::WebCache; 44 45namespace { 46 47const uint32 kFilteredMessageClasses[] = { 48 ChromeMsgStart, 49 ExtensionMsgStart, 50}; 51 52// Logs an action to the extension activity log for the specified profile. Can 53// be called from any thread. 54void AddActionToExtensionActivityLog( 55 Profile* profile, 56 scoped_refptr<extensions::Action> action) { 57#if defined(ENABLE_EXTENSIONS) 58 // The ActivityLog can only be accessed from the main (UI) thread. If we're 59 // running on the wrong thread, re-dispatch from the main thread. 60 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 61 BrowserThread::PostTask( 62 BrowserThread::UI, FROM_HERE, 63 base::Bind(&AddActionToExtensionActivityLog, profile, action)); 64 } else { 65 if (!g_browser_process->profile_manager()->IsValidProfile(profile)) 66 return; 67 // If the action included a URL, check whether it is for an incognito 68 // profile. The check is performed here so that it can safely be done from 69 // the UI thread. 70 if (action->page_url().is_valid() || !action->page_title().empty()) 71 action->set_page_incognito(profile->IsOffTheRecord()); 72 extensions::ActivityLog* activity_log = 73 extensions::ActivityLog::GetInstance(profile); 74 activity_log->LogAction(action); 75 } 76#endif 77} 78 79} // namespace 80 81ChromeRenderMessageFilter::ChromeRenderMessageFilter( 82 int render_process_id, 83 Profile* profile, 84 net::URLRequestContextGetter* request_context) 85 : BrowserMessageFilter(kFilteredMessageClasses, 86 arraysize(kFilteredMessageClasses)), 87 render_process_id_(render_process_id), 88 profile_(profile), 89 off_the_record_(profile_->IsOffTheRecord()), 90 predictor_(profile_->GetNetworkPredictor()), 91 request_context_(request_context), 92 extension_info_map_( 93 extensions::ExtensionSystem::Get(profile)->info_map()), 94 cookie_settings_(CookieSettings::Factory::GetForProfile(profile)) {} 95 96ChromeRenderMessageFilter::~ChromeRenderMessageFilter() { 97} 98 99bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message, 100 bool* message_was_ok) { 101 bool handled = true; 102 IPC_BEGIN_MESSAGE_MAP_EX(ChromeRenderMessageFilter, message, *message_was_ok) 103 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DnsPrefetch, OnDnsPrefetch) 104 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_Preconnect, OnPreconnect) 105 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ResourceTypeStats, 106 OnResourceTypeStats) 107 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_UpdatedCacheStats, 108 OnUpdatedCacheStats) 109 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_FPS, OnFPS) 110 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_V8HeapStats, OnV8HeapStats) 111 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToExtension, 112 OnOpenChannelToExtension) 113 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToTab, OnOpenChannelToTab) 114 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OpenChannelToNativeApp, 115 OnOpenChannelToNativeApp) 116 IPC_MESSAGE_HANDLER_DELAY_REPLY(ExtensionHostMsg_GetMessageBundle, 117 OnGetExtensionMessageBundle) 118 IPC_MESSAGE_HANDLER(ExtensionHostMsg_CloseChannel, OnExtensionCloseChannel) 119 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddAPIActionToActivityLog, 120 OnAddAPIActionToExtensionActivityLog); 121 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddDOMActionToActivityLog, 122 OnAddDOMActionToExtensionActivityLog); 123 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AddEventToActivityLog, 124 OnAddEventToExtensionActivityLog); 125 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowDatabase, OnAllowDatabase) 126 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowDOMStorage, OnAllowDOMStorage) 127 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowFileSystem, OnAllowFileSystem) 128 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AllowIndexedDB, OnAllowIndexedDB) 129 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardRead, 130 OnCanTriggerClipboardRead) 131 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CanTriggerClipboardWrite, 132 OnCanTriggerClipboardWrite) 133 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_IsCrashReportingEnabled, 134 OnIsCrashReportingEnabled) 135 IPC_MESSAGE_UNHANDLED(handled = false) 136 IPC_END_MESSAGE_MAP() 137 138 return handled; 139} 140 141void ChromeRenderMessageFilter::OverrideThreadForMessage( 142 const IPC::Message& message, BrowserThread::ID* thread) { 143 switch (message.type()) { 144 case ChromeViewHostMsg_ResourceTypeStats::ID: 145 case ExtensionHostMsg_CloseChannel::ID: 146 case ChromeViewHostMsg_UpdatedCacheStats::ID: 147 *thread = BrowserThread::UI; 148 break; 149 default: 150 break; 151 } 152} 153 154net::HostResolver* ChromeRenderMessageFilter::GetHostResolver() { 155 return request_context_->GetURLRequestContext()->host_resolver(); 156} 157 158void ChromeRenderMessageFilter::OnDnsPrefetch( 159 const std::vector<std::string>& hostnames) { 160 if (predictor_) 161 predictor_->DnsPrefetchList(hostnames); 162} 163 164void ChromeRenderMessageFilter::OnPreconnect(const GURL& url) { 165 if (predictor_) 166 predictor_->PreconnectUrl( 167 url, GURL(), chrome_browser_net::UrlInfo::MOUSE_OVER_MOTIVATED, 1); 168} 169 170void ChromeRenderMessageFilter::OnResourceTypeStats( 171 const WebCache::ResourceTypeStats& stats) { 172 HISTOGRAM_COUNTS("WebCoreCache.ImagesSizeKB", 173 static_cast<int>(stats.images.size / 1024)); 174 HISTOGRAM_COUNTS("WebCoreCache.CSSStylesheetsSizeKB", 175 static_cast<int>(stats.cssStyleSheets.size / 1024)); 176 HISTOGRAM_COUNTS("WebCoreCache.ScriptsSizeKB", 177 static_cast<int>(stats.scripts.size / 1024)); 178 HISTOGRAM_COUNTS("WebCoreCache.XSLStylesheetsSizeKB", 179 static_cast<int>(stats.xslStyleSheets.size / 1024)); 180 HISTOGRAM_COUNTS("WebCoreCache.FontsSizeKB", 181 static_cast<int>(stats.fonts.size / 1024)); 182 183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 184#if defined(ENABLE_TASK_MANAGER) 185 TaskManager::GetInstance()->model()->NotifyResourceTypeStats(peer_pid(), 186 stats); 187#endif // defined(ENABLE_TASK_MANAGER) 188} 189 190void ChromeRenderMessageFilter::OnUpdatedCacheStats( 191 const WebCache::UsageStats& stats) { 192 WebCacheManager::GetInstance()->ObserveStats(render_process_id_, stats); 193} 194 195void ChromeRenderMessageFilter::OnFPS(int routing_id, float fps) { 196 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 197 BrowserThread::PostTask( 198 BrowserThread::UI, FROM_HERE, 199 base::Bind( 200 &ChromeRenderMessageFilter::OnFPS, this, 201 routing_id, fps)); 202 return; 203 } 204 205#if defined(ENABLE_TASK_MANAGER) 206 TaskManager::GetInstance()->model()->NotifyFPS( 207 peer_pid(), routing_id, fps); 208#endif // defined(ENABLE_TASK_MANAGER) 209} 210 211void ChromeRenderMessageFilter::OnV8HeapStats(int v8_memory_allocated, 212 int v8_memory_used) { 213 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 214 BrowserThread::PostTask( 215 BrowserThread::UI, FROM_HERE, 216 base::Bind(&ChromeRenderMessageFilter::OnV8HeapStats, this, 217 v8_memory_allocated, v8_memory_used)); 218 return; 219 } 220 221 base::ProcessId renderer_id = peer_pid(); 222 223#if defined(ENABLE_TASK_MANAGER) 224 TaskManager::GetInstance()->model()->NotifyV8HeapStats( 225 renderer_id, 226 static_cast<size_t>(v8_memory_allocated), 227 static_cast<size_t>(v8_memory_used)); 228#endif // defined(ENABLE_TASK_MANAGER) 229 230 V8HeapStatsDetails details(v8_memory_allocated, v8_memory_used); 231 content::NotificationService::current()->Notify( 232 chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED, 233 content::Source<const base::ProcessId>(&renderer_id), 234 content::Details<const V8HeapStatsDetails>(&details)); 235} 236 237void ChromeRenderMessageFilter::OnOpenChannelToExtension( 238 int routing_id, 239 const ExtensionMsg_ExternalConnectionInfo& info, 240 const std::string& channel_name, 241 bool include_tls_channel_id, 242 int* port_id) { 243 int port2_id; 244 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id); 245 246 BrowserThread::PostTask( 247 BrowserThread::UI, FROM_HERE, 248 base::Bind(&ChromeRenderMessageFilter::OpenChannelToExtensionOnUIThread, 249 this, render_process_id_, routing_id, port2_id, info, 250 channel_name, include_tls_channel_id)); 251} 252 253void ChromeRenderMessageFilter::OpenChannelToExtensionOnUIThread( 254 int source_process_id, int source_routing_id, 255 int receiver_port_id, 256 const ExtensionMsg_ExternalConnectionInfo& info, 257 const std::string& channel_name, 258 bool include_tls_channel_id) { 259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 260 extensions::MessageService::Get(profile_)->OpenChannelToExtension( 261 source_process_id, source_routing_id, receiver_port_id, 262 info.source_id, info.target_id, info.source_url, channel_name, 263 include_tls_channel_id); 264} 265 266void ChromeRenderMessageFilter::OnOpenChannelToNativeApp( 267 int routing_id, 268 const std::string& source_extension_id, 269 const std::string& native_app_name, 270 int* port_id) { 271 int port2_id; 272 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id); 273 274 BrowserThread::PostTask( 275 BrowserThread::UI, FROM_HERE, 276 base::Bind(&ChromeRenderMessageFilter::OpenChannelToNativeAppOnUIThread, 277 this, routing_id, port2_id, source_extension_id, 278 native_app_name)); 279} 280 281void ChromeRenderMessageFilter::OpenChannelToNativeAppOnUIThread( 282 int source_routing_id, 283 int receiver_port_id, 284 const std::string& source_extension_id, 285 const std::string& native_app_name) { 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 extensions::MessageService::Get(profile_)->OpenChannelToNativeApp( 288 render_process_id_, source_routing_id, receiver_port_id, 289 source_extension_id, native_app_name); 290} 291 292void ChromeRenderMessageFilter::OnOpenChannelToTab( 293 int routing_id, int tab_id, const std::string& extension_id, 294 const std::string& channel_name, int* port_id) { 295 int port2_id; 296 extensions::MessageService::AllocatePortIdPair(port_id, &port2_id); 297 298 BrowserThread::PostTask( 299 BrowserThread::UI, FROM_HERE, 300 base::Bind(&ChromeRenderMessageFilter::OpenChannelToTabOnUIThread, this, 301 render_process_id_, routing_id, port2_id, tab_id, extension_id, 302 channel_name)); 303} 304 305void ChromeRenderMessageFilter::OpenChannelToTabOnUIThread( 306 int source_process_id, int source_routing_id, 307 int receiver_port_id, 308 int tab_id, 309 const std::string& extension_id, 310 const std::string& channel_name) { 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 312 extensions::MessageService::Get(profile_)->OpenChannelToTab( 313 source_process_id, source_routing_id, receiver_port_id, 314 tab_id, extension_id, channel_name); 315} 316 317void ChromeRenderMessageFilter::OnGetExtensionMessageBundle( 318 const std::string& extension_id, IPC::Message* reply_msg) { 319 const extensions::Extension* extension = 320 extension_info_map_->extensions().GetByID(extension_id); 321 base::FilePath extension_path; 322 std::string default_locale; 323 if (extension) { 324 extension_path = extension->path(); 325 default_locale = extensions::LocaleInfo::GetDefaultLocale(extension); 326 } 327 328 BrowserThread::PostTask( 329 BrowserThread::FILE, FROM_HERE, 330 base::Bind( 331 &ChromeRenderMessageFilter::OnGetExtensionMessageBundleOnFileThread, 332 this, extension_path, extension_id, default_locale, reply_msg)); 333} 334 335void ChromeRenderMessageFilter::OnGetExtensionMessageBundleOnFileThread( 336 const base::FilePath& extension_path, 337 const std::string& extension_id, 338 const std::string& default_locale, 339 IPC::Message* reply_msg) { 340 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 341 342 scoped_ptr<extensions::MessageBundle::SubstitutionMap> dictionary_map( 343 extension_file_util::LoadMessageBundleSubstitutionMap( 344 extension_path, extension_id, default_locale)); 345 346 ExtensionHostMsg_GetMessageBundle::WriteReplyParams(reply_msg, 347 *dictionary_map); 348 Send(reply_msg); 349} 350 351void ChromeRenderMessageFilter::OnExtensionCloseChannel( 352 int port_id, 353 const std::string& error_message) { 354 if (!content::RenderProcessHost::FromID(render_process_id_)) 355 return; // To guard against crash in browser_tests shutdown. 356 357 extensions::MessageService* message_service = 358 extensions::MessageService::Get(profile_); 359 if (message_service) 360 message_service->CloseChannel(port_id, error_message); 361} 362 363void ChromeRenderMessageFilter::OnAddAPIActionToExtensionActivityLog( 364 const std::string& extension_id, 365 const ExtensionHostMsg_APIActionOrEvent_Params& params) { 366 scoped_refptr<extensions::Action> action = new extensions::Action( 367 extension_id, base::Time::Now(), extensions::Action::ACTION_API_CALL, 368 params.api_call); 369 action->set_args(make_scoped_ptr(params.arguments.DeepCopy())); 370 if (!params.extra.empty()) { 371 action->mutable_other()->SetString( 372 activity_log_constants::kActionExtra, params.extra); 373 } 374 AddActionToExtensionActivityLog(profile_, action); 375} 376 377void ChromeRenderMessageFilter::OnAddDOMActionToExtensionActivityLog( 378 const std::string& extension_id, 379 const ExtensionHostMsg_DOMAction_Params& params) { 380 scoped_refptr<extensions::Action> action = new extensions::Action( 381 extension_id, base::Time::Now(), extensions::Action::ACTION_DOM_ACCESS, 382 params.api_call); 383 action->set_args(make_scoped_ptr(params.arguments.DeepCopy())); 384 action->set_page_url(params.url); 385 action->set_page_title(base::UTF16ToUTF8(params.url_title)); 386 action->mutable_other()->SetInteger(activity_log_constants::kActionDomVerb, 387 params.call_type); 388 AddActionToExtensionActivityLog(profile_, action); 389} 390 391void ChromeRenderMessageFilter::OnAddEventToExtensionActivityLog( 392 const std::string& extension_id, 393 const ExtensionHostMsg_APIActionOrEvent_Params& params) { 394 scoped_refptr<extensions::Action> action = new extensions::Action( 395 extension_id, base::Time::Now(), extensions::Action::ACTION_API_EVENT, 396 params.api_call); 397 action->set_args(make_scoped_ptr(params.arguments.DeepCopy())); 398 if (!params.extra.empty()) { 399 action->mutable_other()->SetString(activity_log_constants::kActionExtra, 400 params.extra); 401 } 402 AddActionToExtensionActivityLog(profile_, action); 403} 404 405void ChromeRenderMessageFilter::OnAllowDatabase( 406 int render_frame_id, 407 const GURL& origin_url, 408 const GURL& top_origin_url, 409 const base::string16& name, 410 const base::string16& display_name, 411 bool* allowed) { 412 *allowed = 413 cookie_settings_->IsSettingCookieAllowed(origin_url, top_origin_url); 414 BrowserThread::PostTask( 415 BrowserThread::UI, FROM_HERE, 416 base::Bind(&TabSpecificContentSettings::WebDatabaseAccessed, 417 render_process_id_, render_frame_id, origin_url, name, 418 display_name, !*allowed)); 419} 420 421void ChromeRenderMessageFilter::OnAllowDOMStorage(int render_frame_id, 422 const GURL& origin_url, 423 const GURL& top_origin_url, 424 bool local, 425 bool* allowed) { 426 *allowed = 427 cookie_settings_->IsSettingCookieAllowed(origin_url, top_origin_url); 428 // Record access to DOM storage for potential display in UI. 429 BrowserThread::PostTask( 430 BrowserThread::UI, FROM_HERE, 431 base::Bind(&TabSpecificContentSettings::DOMStorageAccessed, 432 render_process_id_, render_frame_id, origin_url, local, 433 !*allowed)); 434} 435 436void ChromeRenderMessageFilter::OnAllowFileSystem(int render_frame_id, 437 const GURL& origin_url, 438 const GURL& top_origin_url, 439 bool* allowed) { 440 *allowed = 441 cookie_settings_->IsSettingCookieAllowed(origin_url, top_origin_url); 442 // Record access to file system for potential display in UI. 443 BrowserThread::PostTask( 444 BrowserThread::UI, FROM_HERE, 445 base::Bind(&TabSpecificContentSettings::FileSystemAccessed, 446 render_process_id_, render_frame_id, origin_url, !*allowed)); 447} 448 449void ChromeRenderMessageFilter::OnAllowIndexedDB(int render_frame_id, 450 const GURL& origin_url, 451 const GURL& top_origin_url, 452 const base::string16& name, 453 bool* allowed) { 454 *allowed = 455 cookie_settings_->IsSettingCookieAllowed(origin_url, top_origin_url); 456 BrowserThread::PostTask( 457 BrowserThread::UI, FROM_HERE, 458 base::Bind(&TabSpecificContentSettings::IndexedDBAccessed, 459 render_process_id_, render_frame_id, origin_url, name, 460 !*allowed)); 461} 462 463void ChromeRenderMessageFilter::OnCanTriggerClipboardRead( 464 const GURL& origin, bool* allowed) { 465 *allowed = extension_info_map_->SecurityOriginHasAPIPermission( 466 origin, render_process_id_, APIPermission::kClipboardRead); 467} 468 469void ChromeRenderMessageFilter::OnCanTriggerClipboardWrite( 470 const GURL& origin, bool* allowed) { 471 // Since all extensions could historically write to the clipboard, preserve it 472 // for compatibility. 473 *allowed = (origin.SchemeIs(extensions::kExtensionScheme) || 474 extension_info_map_->SecurityOriginHasAPIPermission( 475 origin, render_process_id_, APIPermission::kClipboardWrite)); 476} 477 478void ChromeRenderMessageFilter::OnIsCrashReportingEnabled(bool* enabled) { 479 *enabled = MetricsServiceHelper::IsCrashReportingEnabled(); 480} 481