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