1 // Copyright (c) 2010 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.
5 #include "chrome/renderer/render_thread.h"
12 #include "base/command_line.h"
13 #include "base/field_trial.h"
14 #include "base/lazy_instance.h"
15 #include "base/logging.h"
16 #include "base/nullable_string16.h"
17 #include "base/process_util.h"
18 #include "base/shared_memory.h"
19 #include "base/stats_table.h"
20 #include "base/string_util.h"
21 #include "base/task.h"
22 #include "base/thread_local.h"
23 #include "base/trace_event.h"
24 #include "base/utf_string_conversions.h"
25 #include "base/values.h"
26 #include "chrome/common/appcache/appcache_dispatcher.h"
27 #include "chrome/common/child_process_logging.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/db_message_filter.h"
30 #include "chrome/common/dom_storage_common.h"
31 #include "chrome/common/plugin_messages.h"
32 #include "chrome/common/render_messages.h"
33 #include "chrome/common/render_messages_params.h"
34 #include "chrome/common/renderer_preferences.h"
35 #include "chrome/common/url_constants.h"
36 #include "chrome/common/web_database_observer_impl.h"
37 #include "chrome/plugin/npobject_util.h"
40 #include "chrome/plugin/plugin_channel.h"
42 #include "base/scoped_handle.h"
43 #include "chrome/plugin/plugin_channel_base.h"
45 #include "chrome/renderer/automation/dom_automation_v8_extension.h"
46 #include "chrome/renderer/cookie_message_filter.h"
47 #include "chrome/renderer/devtools_agent_filter.h"
48 #include "chrome/renderer/extension_groups.h"
49 #include "chrome/renderer/extensions/chrome_app_bindings.h"
50 #include "chrome/renderer/extensions/extension_renderer_info.h"
51 #include "chrome/renderer/extensions/event_bindings.h"
52 #include "chrome/renderer/extensions/extension_process_bindings.h"
53 #include "chrome/renderer/extensions/js_only_v8_extensions.h"
54 #include "chrome/renderer/extensions/renderer_extension_bindings.h"
55 #include "chrome/renderer/external_extension.h"
56 #include "chrome/renderer/gpu_channel_host.h"
57 #include "chrome/renderer/gpu_video_service_host.h"
58 #include "chrome/renderer/indexed_db_dispatcher.h"
59 #include "chrome/renderer/loadtimes_extension_bindings.h"
60 #include "chrome/renderer/net/renderer_net_predictor.h"
61 #include "chrome/renderer/plugin_channel_host.h"
62 #include "chrome/renderer/render_process_impl.h"
63 #include "chrome/renderer/render_view.h"
64 #include "chrome/renderer/render_view_visitor.h"
65 #include "chrome/renderer/renderer_histogram_snapshots.h"
66 #include "chrome/renderer/renderer_webidbfactory_impl.h"
67 #include "chrome/renderer/renderer_webkitclient_impl.h"
68 #include "chrome/renderer/spellchecker/spellcheck.h"
69 #include "chrome/renderer/user_script_slave.h"
70 #include "ipc/ipc_channel_handle.h"
71 #include "ipc/ipc_message.h"
72 #include "ipc/ipc_platform_file.h"
73 #include "net/base/net_util.h"
74 #include "third_party/sqlite/sqlite3.h"
75 #include "third_party/tcmalloc/chromium/src/google/malloc_extension.h"
76 #include "third_party/WebKit/WebKit/chromium/public/WebCache.h"
77 #include "third_party/WebKit/WebKit/chromium/public/WebColor.h"
78 #include "third_party/WebKit/WebKit/chromium/public/WebCrossOriginPreflightResultCache.h"
79 #include "third_party/WebKit/WebKit/chromium/public/WebDatabase.h"
80 #include "third_party/WebKit/WebKit/chromium/public/WebFontCache.h"
81 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
82 #include "third_party/WebKit/WebKit/chromium/public/WebKit.h"
83 #include "third_party/WebKit/WebKit/chromium/public/WebRuntimeFeatures.h"
84 #include "third_party/WebKit/WebKit/chromium/public/WebScriptController.h"
85 #include "third_party/WebKit/WebKit/chromium/public/WebSecurityPolicy.h"
86 #include "third_party/WebKit/WebKit/chromium/public/WebStorageEventDispatcher.h"
87 #include "third_party/WebKit/WebKit/chromium/public/WebString.h"
88 #include "third_party/WebKit/WebKit/chromium/public/WebView.h"
89 #include "webkit/extensions/v8/benchmarking_extension.h"
90 #include "webkit/extensions/v8/gears_extension.h"
91 #include "webkit/extensions/v8/playback_extension.h"
92 #include "v8/include/v8.h"
99 #if defined(OS_MACOSX)
100 #include "chrome/app/breakpad_mac.h"
103 #if defined(OS_POSIX)
104 #include "ipc/ipc_channel_posix.h"
107 using WebKit::WebCache
;
108 using WebKit::WebCrossOriginPreflightResultCache
;
109 using WebKit::WebFontCache
;
110 using WebKit::WebFrame
;
111 using WebKit::WebRuntimeFeatures
;
112 using WebKit::WebSecurityPolicy
;
113 using WebKit::WebScriptController
;
114 using WebKit::WebString
;
115 using WebKit::WebStorageEventDispatcher
;
116 using WebKit::WebView
;
119 static const unsigned int kCacheStatsDelayMS
= 2000 /* milliseconds */;
120 static const double kInitialIdleHandlerDelayS
= 1.0 /* seconds */;
121 static const double kInitialExtensionIdleHandlerDelayS
= 5.0 /* seconds */;
122 static const int64 kMaxExtensionIdleHandlerDelayS
= 5*60 /* seconds */;
124 static const int kPrelauchGpuPercentage
= 5;
125 static const int kPrelauchGpuProcessDelayMS
= 10000;
127 // Keep the global RenderThread in a TLS slot so it is impossible to access
128 // incorrectly from the wrong thread.
129 static base::LazyInstance
<base::ThreadLocalPointer
<RenderThread
> > lazy_tls(
130 base::LINKER_INITIALIZED
);
132 #if defined(OS_POSIX)
133 class SuicideOnChannelErrorFilter
: public IPC::ChannelProxy::MessageFilter
{
134 void OnChannelError() {
135 // On POSIX, at least, one can install an unload handler which loops
136 // forever and leave behind a renderer process which eats 100% CPU forever.
138 // This is because the terminate signals (ViewMsg_ShouldClose and the error
139 // from the IPC channel) are routed to the main message loop but never
140 // processed (because that message loop is stuck in V8).
142 // One could make the browser SIGKILL the renderers, but that leaves open a
143 // large window where a browser failure (or a user, manually terminating
144 // the browser because "it's stuck") will leave behind a process eating all
147 // So, we install a filter on the channel so that we can process this event
148 // here and kill the process.
150 #if defined(OS_MACOSX)
151 // TODO(viettrungluu): crbug.com/28547: The following is needed, as a
152 // stopgap, to avoid leaking due to not releasing Breakpad properly.
153 // TODO(viettrungluu): Investigate why this is being called.
154 if (IsCrashReporterEnabled()) {
155 LOG(INFO
) << "Cleaning up Breakpad.";
156 DestructCrashReporter();
158 LOG(INFO
) << "Breakpad not enabled; no clean-up needed.";
167 class RenderViewContentSettingsSetter
: public RenderViewVisitor
{
169 RenderViewContentSettingsSetter(const GURL
& url
,
170 const ContentSettings
& content_settings
)
172 content_settings_(content_settings
) {
175 virtual bool Visit(RenderView
* render_view
) {
176 if (GURL(render_view
->webview()->mainFrame()->url()) == url_
)
177 render_view
->SetContentSettings(content_settings_
);
183 ContentSettings content_settings_
;
185 DISALLOW_COPY_AND_ASSIGN(RenderViewContentSettingsSetter
);
188 class RenderViewZoomer
: public RenderViewVisitor
{
190 RenderViewZoomer(const GURL
& url
, int zoom_level
)
191 : zoom_level_(zoom_level
) {
192 host_
= net::GetHostOrSpecFromURL(url
);
195 virtual bool Visit(RenderView
* render_view
) {
196 WebView
* webview
= render_view
->webview(); // Guaranteed non-NULL.
197 if (net::GetHostOrSpecFromURL(GURL(webview
->mainFrame()->url())) == host_
)
198 webview
->setZoomLevel(false, zoom_level_
);
206 DISALLOW_COPY_AND_ASSIGN(RenderViewZoomer
);
209 bool IsSpeechInputEnabled(const CommandLine
& command_line
) {
210 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
211 return !command_line
.HasSwitch(switches::kDisableSpeechInput
);
213 return command_line
.HasSwitch(switches::kEnableSpeechInput
);
218 // When we run plugins in process, we actually run them on the render thread,
219 // which means that we need to make the render thread pump UI events.
220 RenderThread::RenderThread() {
224 RenderThread::RenderThread(const std::string
& channel_name
)
225 : ChildThread(channel_name
) {
229 void RenderThread::Init() {
230 TRACE_EVENT_BEGIN("RenderThread::Init", 0, "");
232 lazy_tls
.Pointer()->Set(this);
234 // If you are running plugins in this thread you need COM active but in
235 // the normal case you don't.
236 if (RenderProcessImpl::InProcessPlugins())
240 std::string type_str
= CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
241 switches::kProcessType
);
242 // In single process the single process is all there is.
243 is_extension_process_
= type_str
== switches::kExtensionProcess
||
244 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess
);
245 is_incognito_process_
= false;
246 suspend_webkit_shared_timer_
= true;
247 notify_webkit_of_modal_loop_
= true;
248 plugin_refresh_allowed_
= true;
249 cache_stats_task_pending_
= false;
251 hidden_widget_count_
= 0;
252 idle_notification_delay_in_s_
= is_extension_process_
?
253 kInitialExtensionIdleHandlerDelayS
: kInitialIdleHandlerDelayS
;
254 task_factory_
.reset(new ScopedRunnableMethodFactory
<RenderThread
>(this));
256 visited_link_slave_
.reset(new VisitedLinkSlave());
257 user_script_slave_
.reset(new UserScriptSlave());
258 renderer_net_predictor_
.reset(new RendererNetPredictor());
259 histogram_snapshots_
.reset(new RendererHistogramSnapshots());
260 appcache_dispatcher_
.reset(new AppCacheDispatcher(this));
261 indexed_db_dispatcher_
.reset(new IndexedDBDispatcher());
262 spellchecker_
.reset(new SpellCheck());
264 devtools_agent_filter_
= new DevToolsAgentFilter();
265 AddFilter(devtools_agent_filter_
.get());
267 db_message_filter_
= new DBMessageFilter();
268 AddFilter(db_message_filter_
.get());
270 cookie_message_filter_
= new CookieMessageFilter();
271 AddFilter(cookie_message_filter_
.get());
273 #if defined(OS_POSIX)
274 suicide_on_channel_error_filter_
= new SuicideOnChannelErrorFilter
;
275 AddFilter(suicide_on_channel_error_filter_
.get());
278 // Establish a channel to the GPU process asynchronously if requested. If the
279 // channel is established in time, EstablishGpuChannelSync will not block when
280 // it is later called. Delays by a fixed period of time to avoid loading the
281 // GPU immediately in an attempt to not slow startup time.
282 scoped_refptr
<FieldTrial
> prelaunch_trial(
283 new FieldTrial("PrelaunchGpuProcessExperiment", 100));
284 int prelaunch_group
= prelaunch_trial
->AppendGroup("prelaunch_gpu_process",
285 kPrelauchGpuPercentage
);
286 if (prelaunch_group
== prelaunch_trial
->group() ||
287 CommandLine::ForCurrentProcess()->HasSwitch(
288 switches::kPrelaunchGpuProcess
)) {
289 message_loop()->PostDelayedTask(FROM_HERE
,
290 task_factory_
->NewRunnableMethod(
291 &RenderThread::EstablishGpuChannel
),
292 kPrelauchGpuProcessDelayMS
);
295 GpuVideoServiceHost::get()->OnRendererThreadInit(MessageLoop::current());
297 TRACE_EVENT_END("RenderThread::Init", 0, "");
300 RenderThread::~RenderThread() {
301 // Wait for all databases to be closed.
302 if (web_database_observer_impl_
.get())
303 web_database_observer_impl_
->WaitForAllDatabasesToClose();
305 // Shutdown in reverse of the initialization order.
306 RemoveFilter(db_message_filter_
.get());
307 db_message_filter_
= NULL
;
308 RemoveFilter(devtools_agent_filter_
.get());
310 // Shutdown the file thread if it's running.
311 if (file_thread_
.get())
312 file_thread_
->Stop();
314 if (webkit_client_
.get())
317 lazy_tls
.Pointer()->Set(NULL
);
321 // Clean up plugin channels before this thread goes away.
322 PluginChannelBase::CleanupChannels();
323 // Don't call COM if the renderer is in the sandbox.
324 if (RenderProcessImpl::InProcessPlugins())
329 RenderThread
* RenderThread::current() {
330 return lazy_tls
.Pointer()->Get();
333 int32
RenderThread::RoutingIDForCurrentContext() {
334 int32 routing_id
= MSG_ROUTING_CONTROL
;
335 if (v8::Context::InContext()) {
336 WebFrame
* frame
= WebFrame::frameForCurrentContext();
338 RenderView
* view
= RenderView::FromWebView(frame
->view());
340 routing_id
= view
->routing_id();
343 DLOG(WARNING
) << "Not called within a script context!";
348 bool RenderThread::Send(IPC::Message
* msg
) {
349 // Certain synchronous messages can result in an app-modal cookie prompt.
350 // This could cause a complete hang of Chrome if a windowed plug-in is trying
351 // to communicate with the renderer thread since the browser's UI thread
352 // could be stuck (within a Windows API call) trying to synchronously
353 // communicate with the plug-in. The remedy is to pump messages on this
354 // thread while the cookie prompt is showing. This creates an opportunity
355 // for re-entrancy into WebKit, so we need to take care to disable callbacks,
356 // timers, and pending network loads that could trigger such callbacks.
358 bool pumping_events
= false, may_show_cookie_prompt
= false;
359 if (msg
->is_sync()) {
360 if (msg
->is_caller_pumping_messages()) {
361 pumping_events
= true;
363 switch (msg
->type()) {
364 case ViewHostMsg_GetCookies::ID
:
365 case ViewHostMsg_GetRawCookies::ID
:
366 case ViewHostMsg_DOMStorageSetItem::ID
:
367 case ViewHostMsg_SyncLoad::ID
:
368 case ViewHostMsg_AllowDatabase::ID
:
369 may_show_cookie_prompt
= true;
370 pumping_events
= true;
376 bool suspend_webkit_shared_timer
= true; // default value
377 std::swap(suspend_webkit_shared_timer
, suspend_webkit_shared_timer_
);
379 bool notify_webkit_of_modal_loop
= true; // default value
380 std::swap(notify_webkit_of_modal_loop
, notify_webkit_of_modal_loop_
);
382 gfx::NativeViewId host_window
= 0;
384 if (pumping_events
) {
385 // See ViewMsg_SignalCookiePromptEvent.
386 if (may_show_cookie_prompt
) {
387 static_cast<IPC::SyncMessage
*>(msg
)->set_pump_messages_event(
388 cookie_message_filter_
->pump_messages_event());
391 if (suspend_webkit_shared_timer
)
392 webkit_client_
->SuspendSharedTimer();
394 if (notify_webkit_of_modal_loop
)
395 WebView::willEnterModalLoop();
397 RenderWidget
* widget
=
398 static_cast<RenderWidget
*>(ResolveRoute(msg
->routing_id()));
400 host_window
= widget
->host_window();
401 PluginChannelHost::Broadcast(
402 new PluginMsg_SignalModalDialogEvent(host_window
));
406 bool rv
= ChildThread::Send(msg
);
408 if (pumping_events
) {
410 PluginChannelHost::Broadcast(
411 new PluginMsg_ResetModalDialogEvent(host_window
));
414 if (notify_webkit_of_modal_loop
)
415 WebView::didExitModalLoop();
417 if (suspend_webkit_shared_timer
)
418 webkit_client_
->ResumeSharedTimer();
420 // We may end up nesting calls to Send, so we defer the reset until we
421 // return to the top-most message loop.
422 if (may_show_cookie_prompt
&&
423 cookie_message_filter_
->pump_messages_event()->IsSignaled()) {
424 MessageLoop::current()->PostNonNestableTask(FROM_HERE
,
425 NewRunnableMethod(cookie_message_filter_
.get(),
426 &CookieMessageFilter::ResetPumpMessagesEvent
));
433 void RenderThread::AddRoute(int32 routing_id
,
434 IPC::Channel::Listener
* listener
) {
436 child_process_logging::SetNumberOfViews(widget_count_
);
437 return ChildThread::AddRoute(routing_id
, listener
);
440 void RenderThread::RemoveRoute(int32 routing_id
) {
442 child_process_logging::SetNumberOfViews(widget_count_
);
443 return ChildThread::RemoveRoute(routing_id
);
446 void RenderThread::AddFilter(IPC::ChannelProxy::MessageFilter
* filter
) {
447 channel()->AddFilter(filter
);
450 void RenderThread::RemoveFilter(IPC::ChannelProxy::MessageFilter
* filter
) {
451 channel()->RemoveFilter(filter
);
454 void RenderThread::WidgetHidden() {
455 DCHECK(hidden_widget_count_
< widget_count_
);
456 hidden_widget_count_
++;
457 if (!is_extension_process_
&&
458 widget_count_
&& hidden_widget_count_
== widget_count_
)
459 ScheduleIdleHandler(kInitialIdleHandlerDelayS
);
462 void RenderThread::WidgetRestored() {
463 DCHECK_GT(hidden_widget_count_
, 0);
464 hidden_widget_count_
--;
465 if (!is_extension_process_
)
469 void RenderThread::DoNotSuspendWebKitSharedTimer() {
470 suspend_webkit_shared_timer_
= false;
473 void RenderThread::DoNotNotifyWebKitOfModalLoop() {
474 notify_webkit_of_modal_loop_
= false;
477 void RenderThread::Resolve(const char* name
, size_t length
) {
478 return renderer_net_predictor_
->Resolve(name
, length
);
481 void RenderThread::SendHistograms(int sequence_number
) {
482 return histogram_snapshots_
->SendHistograms(sequence_number
);
485 void RenderThread::OnUpdateVisitedLinks(base::SharedMemoryHandle table
) {
486 DCHECK(base::SharedMemory::IsHandleValid(table
)) << "Bad table handle";
487 visited_link_slave_
->Init(table
);
490 void RenderThread::OnAddVisitedLinks(
491 const VisitedLinkSlave::Fingerprints
& fingerprints
) {
492 for (size_t i
= 0; i
< fingerprints
.size(); ++i
)
493 WebView::updateVisitedLinkState(fingerprints
[i
]);
496 void RenderThread::OnResetVisitedLinks() {
497 WebView::resetVisitedLinkState();
500 void RenderThread::OnSetContentSettingsForCurrentURL(
502 const ContentSettings
& content_settings
) {
503 RenderViewContentSettingsSetter
setter(url
, content_settings
);
504 RenderView::ForEach(&setter
);
507 void RenderThread::OnSetZoomLevelForCurrentURL(const GURL
& url
,
509 RenderViewZoomer
zoomer(url
, zoom_level
);
510 RenderView::ForEach(&zoomer
);
513 void RenderThread::OnUpdateUserScripts(base::SharedMemoryHandle scripts
) {
514 DCHECK(base::SharedMemory::IsHandleValid(scripts
)) << "Bad scripts handle";
515 user_script_slave_
->UpdateScripts(scripts
);
516 UpdateActiveExtensions();
519 void RenderThread::OnSetExtensionFunctionNames(
520 const std::vector
<std::string
>& names
) {
521 ExtensionProcessBindings::SetFunctionNames(names
);
524 void RenderThread::OnExtensionsUpdated(
525 const ViewMsg_ExtensionsUpdated_Params
& params
) {
526 ExtensionRendererInfo::UpdateExtensions(params
);
529 void RenderThread::OnPageActionsUpdated(
530 const std::string
& extension_id
,
531 const std::vector
<std::string
>& page_actions
) {
532 ExtensionProcessBindings::SetPageActions(extension_id
, page_actions
);
535 void RenderThread::OnExtensionSetAPIPermissions(
536 const std::string
& extension_id
,
537 const std::vector
<std::string
>& permissions
) {
538 ExtensionProcessBindings::SetAPIPermissions(extension_id
, permissions
);
540 // This is called when starting a new extension page, so start the idle
542 ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayS
);
544 UpdateActiveExtensions();
547 void RenderThread::OnExtensionSetHostPermissions(
548 const GURL
& extension_url
, const std::vector
<URLPattern
>& permissions
) {
549 ExtensionProcessBindings::SetHostPermissions(extension_url
, permissions
);
552 void RenderThread::OnExtensionSetIncognitoEnabled(
553 const std::string
& extension_id
, bool enabled
, bool incognito_split_mode
) {
554 ExtensionProcessBindings::SetIncognitoEnabled(extension_id
, enabled
,
555 incognito_split_mode
);
558 void RenderThread::OnDOMStorageEvent(
559 const ViewMsg_DOMStorageEvent_Params
& params
) {
560 if (!dom_storage_event_dispatcher_
.get())
561 dom_storage_event_dispatcher_
.reset(WebStorageEventDispatcher::create());
562 dom_storage_event_dispatcher_
->dispatchStorageEvent(params
.key_
,
563 params
.old_value_
, params
.new_value_
, params
.origin_
, params
.url_
,
564 params
.storage_type_
== DOM_STORAGE_LOCAL
);
567 void RenderThread::OnControlMessageReceived(const IPC::Message
& msg
) {
568 // Some messages are handled by delegates.
569 if (appcache_dispatcher_
->OnMessageReceived(msg
))
571 if (indexed_db_dispatcher_
->OnMessageReceived(msg
))
574 IPC_BEGIN_MESSAGE_MAP(RenderThread
, msg
)
575 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable
, OnUpdateVisitedLinks
)
576 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_Add
, OnAddVisitedLinks
)
577 IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_Reset
, OnResetVisitedLinks
)
578 IPC_MESSAGE_HANDLER(ViewMsg_SetContentSettingsForCurrentURL
,
579 OnSetContentSettingsForCurrentURL
)
580 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForCurrentURL
,
581 OnSetZoomLevelForCurrentURL
)
582 IPC_MESSAGE_HANDLER(ViewMsg_SetIsIncognitoProcess
, OnSetIsIncognitoProcess
)
583 IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID
, OnSetNextPageID
)
584 IPC_MESSAGE_HANDLER(ViewMsg_SetCSSColors
, OnSetCSSColors
)
585 // TODO(port): removed from render_messages_internal.h;
586 // is there a new non-windows message I should add here?
587 IPC_MESSAGE_HANDLER(ViewMsg_New
, OnCreateNewView
)
588 IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities
, OnSetCacheCapacities
)
589 IPC_MESSAGE_HANDLER(ViewMsg_GetRendererHistograms
,
590 OnGetRendererHistograms
)
591 #if defined(USE_TCMALLOC)
592 IPC_MESSAGE_HANDLER(ViewMsg_GetRendererTcmalloc
,
593 OnGetRendererTcmalloc
)
595 IPC_MESSAGE_HANDLER(ViewMsg_GetV8HeapStats
, OnGetV8HeapStats
)
596 IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats
,
597 OnGetCacheResourceStats
)
598 IPC_MESSAGE_HANDLER(ViewMsg_UserScripts_UpdatedScripts
,
600 // TODO(rafaelw): create an ExtensionDispatcher that handles extension
601 // messages seperates their handling from the RenderThread.
602 IPC_MESSAGE_HANDLER(ViewMsg_ExtensionMessageInvoke
,
603 OnExtensionMessageInvoke
)
604 IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetFunctionNames
,
605 OnSetExtensionFunctionNames
)
606 IPC_MESSAGE_HANDLER(ViewMsg_ExtensionsUpdated
,
608 IPC_MESSAGE_HANDLER(ViewMsg_PurgeMemory
, OnPurgeMemory
)
609 IPC_MESSAGE_HANDLER(ViewMsg_PurgePluginListCache
,
610 OnPurgePluginListCache
)
611 IPC_MESSAGE_HANDLER(ViewMsg_Extension_UpdatePageActions
,
612 OnPageActionsUpdated
)
613 IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetAPIPermissions
,
614 OnExtensionSetAPIPermissions
)
615 IPC_MESSAGE_HANDLER(ViewMsg_Extension_SetHostPermissions
,
616 OnExtensionSetHostPermissions
)
617 IPC_MESSAGE_HANDLER(ViewMsg_Extension_ExtensionSetIncognitoEnabled
,
618 OnExtensionSetIncognitoEnabled
)
619 IPC_MESSAGE_HANDLER(ViewMsg_DOMStorageEvent
,
621 #if defined(IPC_MESSAGE_LOG_ENABLED)
622 IPC_MESSAGE_HANDLER(ViewMsg_SetIPCLoggingEnabled
,
623 OnSetIPCLoggingEnabled
)
625 IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_Init
,
627 IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_WordAdded
,
628 OnSpellCheckWordAdded
)
629 IPC_MESSAGE_HANDLER(ViewMsg_SpellChecker_EnableAutoSpellCorrect
,
630 OnSpellCheckEnableAutoSpellCorrect
)
631 IPC_MESSAGE_HANDLER(ViewMsg_GpuChannelEstablished
, OnGpuChannelEstablished
)
632 IPC_END_MESSAGE_MAP()
635 void RenderThread::OnSetNextPageID(int32 next_page_id
) {
636 // This should only be called at process initialization time, so we shouldn't
637 // have to worry about thread-safety.
638 RenderView::SetNextPageID(next_page_id
);
641 // Called when to register CSS Color name->system color mappings.
642 // We update the colors one by one and then tell WebKit to refresh all render
644 void RenderThread::OnSetCSSColors(
645 const std::vector
<CSSColors::CSSColorMapping
>& colors
) {
646 EnsureWebKitInitialized();
647 size_t num_colors
= colors
.size();
648 scoped_array
<WebKit::WebColorName
> color_names(
649 new WebKit::WebColorName
[num_colors
]);
650 scoped_array
<WebKit::WebColor
> web_colors(new WebKit::WebColor
[num_colors
]);
652 for (std::vector
<CSSColors::CSSColorMapping
>::const_iterator it
=
656 color_names
[i
] = it
->first
;
657 web_colors
[i
] = it
->second
;
659 WebKit::setNamedColors(color_names
.get(), web_colors
.get(), num_colors
);
662 void RenderThread::OnCreateNewView(const ViewMsg_New_Params
& params
) {
663 EnsureWebKitInitialized();
664 // When bringing in render_view, also bring in webkit's glue and jsbindings.
667 params
.parent_window
,
669 params
.renderer_preferences
,
670 params
.web_preferences
,
671 new SharedRenderViewCounter(0),
673 params
.session_storage_namespace_id
,
677 void RenderThread::OnSetCacheCapacities(size_t min_dead_capacity
,
678 size_t max_dead_capacity
,
680 EnsureWebKitInitialized();
681 WebCache::setCapacities(
682 min_dead_capacity
, max_dead_capacity
, capacity
);
685 void RenderThread::OnGetCacheResourceStats() {
686 EnsureWebKitInitialized();
687 WebCache::ResourceTypeStats stats
;
688 WebCache::getResourceTypeStats(&stats
);
689 Send(new ViewHostMsg_ResourceTypeStats(stats
));
692 void RenderThread::OnGetRendererHistograms(int sequence_number
) {
693 SendHistograms(sequence_number
);
696 #if defined(USE_TCMALLOC)
697 void RenderThread::OnGetRendererTcmalloc() {
699 char buffer
[1024 * 32];
700 base::ProcessId pid
= base::GetCurrentProcId();
701 MallocExtension::instance()->GetStats(buffer
, sizeof(buffer
));
702 result
.append(buffer
);
703 Send(new ViewHostMsg_RendererTcmalloc(pid
, result
));
707 void RenderThread::OnGetV8HeapStats() {
708 v8::HeapStatistics heap_stats
;
709 v8::V8::GetHeapStatistics(&heap_stats
);
710 Send(new ViewHostMsg_V8HeapStats(heap_stats
.total_heap_size(),
711 heap_stats
.used_heap_size()));
714 void RenderThread::InformHostOfCacheStats() {
715 EnsureWebKitInitialized();
716 WebCache::UsageStats stats
;
717 WebCache::getUsageStats(&stats
);
718 Send(new ViewHostMsg_UpdatedCacheStats(stats
));
719 cache_stats_task_pending_
= false;
722 void RenderThread::InformHostOfCacheStatsLater() {
723 // Rate limit informing the host of our cache stats.
724 if (cache_stats_task_pending_
)
727 cache_stats_task_pending_
= true;
728 MessageLoop::current()->PostDelayedTask(FROM_HERE
,
729 task_factory_
->NewRunnableMethod(
730 &RenderThread::InformHostOfCacheStats
),
734 void RenderThread::CloseCurrentConnections() {
735 Send(new ViewHostMsg_CloseCurrentConnections());
738 void RenderThread::SetCacheMode(bool enabled
) {
739 Send(new ViewHostMsg_SetCacheMode(enabled
));
742 void RenderThread::ClearCache() {
744 Send(new ViewHostMsg_ClearCache(&rv
));
747 void RenderThread::EnableSpdy(bool enable
) {
748 Send(new ViewHostMsg_EnableSpdy(enable
));
751 void RenderThread::UpdateActiveExtensions() {
752 // In single-process mode, the browser process reports the active extensions.
753 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess
))
756 std::set
<std::string
> active_extensions
;
757 user_script_slave_
->GetActiveExtensions(&active_extensions
);
758 ExtensionProcessBindings::GetActiveExtensions(&active_extensions
);
759 child_process_logging::SetActiveExtensions(active_extensions
);
762 void RenderThread::EstablishGpuChannel() {
763 if (gpu_channel_
.get()) {
764 // Do nothing if we already have a GPU channel or are already
766 if (gpu_channel_
->state() == GpuChannelHost::UNCONNECTED
||
767 gpu_channel_
->state() == GpuChannelHost::CONNECTED
)
770 // Recreate the channel if it has been lost.
771 if (gpu_channel_
->state() == GpuChannelHost::LOST
)
775 if (!gpu_channel_
.get())
776 gpu_channel_
= new GpuChannelHost
;
778 // Ask the browser for the channel name.
779 Send(new ViewHostMsg_EstablishGpuChannel());
782 GpuChannelHost
* RenderThread::EstablishGpuChannelSync() {
783 EstablishGpuChannel();
784 Send(new ViewHostMsg_SynchronizeGpu());
785 return GetGpuChannel();
788 GpuChannelHost
* RenderThread::GetGpuChannel() {
789 if (!gpu_channel_
.get())
792 if (gpu_channel_
->state() != GpuChannelHost::CONNECTED
)
795 return gpu_channel_
.get();
798 static void* CreateHistogram(
799 const char *name
, int min
, int max
, size_t buckets
) {
802 scoped_refptr
<Histogram
> histogram
= Histogram::FactoryGet(
803 name
, min
, max
, buckets
, Histogram::kUmaTargetedHistogramFlag
);
804 // We'll end up leaking these histograms, unless there is some code hiding in
805 // there to do the dec-ref.
806 // TODO(jar): Handle reference counting in webkit glue.
808 return histogram
.get();
811 static void AddHistogramSample(void* hist
, int sample
) {
812 Histogram
* histogram
= static_cast<Histogram
*>(hist
);
813 histogram
->Add(sample
);
816 void RenderThread::EnsureWebKitInitialized() {
817 if (webkit_client_
.get())
820 // For extensions, we want to ensure we call the IdleHandler every so often,
821 // even if the extension keeps up activity.
822 if (is_extension_process_
) {
823 forced_idle_timer_
.Start(
824 base::TimeDelta::FromSeconds(kMaxExtensionIdleHandlerDelayS
),
825 this, &RenderThread::IdleHandler
);
828 v8::V8::SetCounterFunction(StatsTable::FindLocation
);
829 v8::V8::SetCreateHistogramFunction(CreateHistogram
);
830 v8::V8::SetAddHistogramSampleFunction(AddHistogramSample
);
832 webkit_client_
.reset(new RendererWebKitClientImpl
);
833 WebKit::initialize(webkit_client_
.get());
835 WebScriptController::enableV8SingleThreadMode();
837 // chrome: pages should not be accessible by normal content, and should
838 // also be unable to script anything but themselves (to help limit the damage
839 // that a corrupt chrome: page could cause).
840 WebString
chrome_ui_scheme(ASCIIToUTF16(chrome::kChromeUIScheme
));
841 WebSecurityPolicy::registerURLSchemeAsLocal(chrome_ui_scheme
);
842 WebSecurityPolicy::registerURLSchemeAsNoAccess(chrome_ui_scheme
);
844 // chrome-extension: resources shouldn't trigger insecure content warnings.
845 WebString
extension_scheme(ASCIIToUTF16(chrome::kExtensionScheme
));
846 WebSecurityPolicy::registerURLSchemeAsSecure(extension_scheme
);
849 // We don't yet support Gears on non-Windows, so don't tell pages that we do.
850 WebScriptController::registerExtension(extensions_v8::GearsExtension::Get());
852 WebScriptController::registerExtension(
853 extensions_v8::LoadTimesExtension::Get());
854 WebScriptController::registerExtension(
855 extensions_v8::ChromeAppExtension::Get());
856 WebScriptController::registerExtension(
857 extensions_v8::ExternalExtension::Get());
859 // TODO(rafaelw). Note that extension-related v8 extensions are being
860 // bound currently based on is_extension_process_. This means that
861 // non-extension renderers that slip into an extension process (for example,
862 // an extension page opening an iframe) will be extension bindings setup.
863 // This should be relatively rare, and the offending page won't be able to
864 // make extension API requests because it'll be denied on both sides of
865 // the renderer by a permission check. However, this is still fairly lame
866 // and we should consider implementing a V8Proxy delegate that calls out
867 // to the render thread and makes a decision as to whether to bind these
868 // extensions based on the frame's url.
869 // See: crbug.com/53610.
871 if (is_extension_process_
)
872 WebScriptController::registerExtension(ExtensionProcessBindings::Get());
874 WebScriptController::registerExtension(
875 BaseJsV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS
);
876 if (is_extension_process_
)
877 WebScriptController::registerExtension(BaseJsV8Extension::Get());
879 WebScriptController::registerExtension(
880 JsonSchemaJsV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS
);
881 if (is_extension_process_
)
882 WebScriptController::registerExtension(JsonSchemaJsV8Extension::Get());
884 WebScriptController::registerExtension(
885 EventBindings::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS
);
886 if (is_extension_process_
)
887 WebScriptController::registerExtension(EventBindings::Get());
889 WebScriptController::registerExtension(
890 RendererExtensionBindings::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS
);
891 if (is_extension_process_
)
892 WebScriptController::registerExtension(RendererExtensionBindings::Get());
894 WebScriptController::registerExtension(
895 ExtensionApiTestV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS
);
896 if (is_extension_process_
)
897 WebScriptController::registerExtension(
898 ExtensionApiTestV8Extension::Get());
900 web_database_observer_impl_
.reset(new WebDatabaseObserverImpl(this));
901 WebKit::WebDatabase::setObserver(web_database_observer_impl_
.get());
903 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
905 if (command_line
.HasSwitch(switches::kEnableBenchmarking
)) {
906 WebScriptController::registerExtension(
907 extensions_v8::BenchmarkingExtension::Get());
910 if (command_line
.HasSwitch(switches::kPlaybackMode
) ||
911 command_line
.HasSwitch(switches::kRecordMode
) ||
912 command_line
.HasSwitch(switches::kNoJsRandomness
)) {
913 WebScriptController::registerExtension(
914 extensions_v8::PlaybackExtension::Get());
917 if (command_line
.HasSwitch(switches::kDomAutomationController
)) {
918 WebScriptController::registerExtension(DomAutomationV8Extension::Get());
921 WebRuntimeFeatures::enableMediaPlayer(
922 RenderProcess::current()->HasInitializedMediaLibrary());
924 WebRuntimeFeatures::enableSockets(
925 !command_line
.HasSwitch(switches::kDisableWebSockets
));
927 WebRuntimeFeatures::enableDatabase(
928 !command_line
.HasSwitch(switches::kDisableDatabases
));
930 WebRuntimeFeatures::enableApplicationCache(
931 !command_line
.HasSwitch(switches::kDisableApplicationCache
));
933 WebRuntimeFeatures::enableNotifications(
934 !command_line
.HasSwitch(switches::kDisableDesktopNotifications
));
936 WebRuntimeFeatures::enableLocalStorage(
937 !command_line
.HasSwitch(switches::kDisableLocalStorage
));
938 WebRuntimeFeatures::enableSessionStorage(
939 !command_line
.HasSwitch(switches::kDisableSessionStorage
));
941 WebRuntimeFeatures::enableIndexedDatabase(
942 command_line
.HasSwitch(switches::kEnableIndexedDatabase
));
944 WebRuntimeFeatures::enableGeolocation(
945 !command_line
.HasSwitch(switches::kDisableGeolocation
));
947 WebRuntimeFeatures::enableWebGL(
948 !command_line
.HasSwitch(switches::kDisableExperimentalWebGL
));
950 WebRuntimeFeatures::enablePushState(true);
952 WebRuntimeFeatures::enableTouch(
953 command_line
.HasSwitch(switches::kEnableTouch
));
955 WebRuntimeFeatures::enableDeviceMotion(
956 command_line
.HasSwitch(switches::kEnableDeviceMotion
));
958 WebRuntimeFeatures::enableDeviceOrientation(
959 !command_line
.HasSwitch(switches::kDisableDeviceOrientation
));
961 WebRuntimeFeatures::enableSpeechInput(IsSpeechInputEnabled(command_line
));
963 WebRuntimeFeatures::enableFileSystem(
964 command_line
.HasSwitch(switches::kEnableFileSystem
));
967 void RenderThread::IdleHandler() {
968 #if (defined(OS_WIN) || defined(OS_LINUX)) && defined(USE_TCMALLOC)
969 MallocExtension::instance()->ReleaseFreeMemory();
972 v8::V8::IdleNotification();
974 // Schedule next invocation.
975 // Dampen the delay using the algorithm:
976 // delay = delay + 1 / (delay + 2)
977 // Using floor(delay) has a dampening effect such as:
978 // 1s, 1, 1, 2, 2, 2, 2, 3, 3, ...
979 // Note that idle_notification_delay_in_s_ would be reset to
980 // kInitialIdleHandlerDelayS in RenderThread::WidgetHidden.
981 ScheduleIdleHandler(idle_notification_delay_in_s_
+
982 1.0 / (idle_notification_delay_in_s_
+ 2.0));
983 if (is_extension_process_
) {
984 // Dampen the forced delay as well if the extension stays idle for long
986 int64 forced_delay_s
=
987 std::max(static_cast<int64
>(idle_notification_delay_in_s_
),
988 kMaxExtensionIdleHandlerDelayS
);
989 forced_idle_timer_
.Stop();
990 forced_idle_timer_
.Start(
991 base::TimeDelta::FromSeconds(forced_delay_s
),
992 this, &RenderThread::IdleHandler
);
996 void RenderThread::ScheduleIdleHandler(double initial_delay_s
) {
997 idle_notification_delay_in_s_
= initial_delay_s
;
1000 base::TimeDelta::FromSeconds(static_cast<int64
>(initial_delay_s
)),
1001 this, &RenderThread::IdleHandler
);
1004 void RenderThread::OnExtensionMessageInvoke(const std::string
& function_name
,
1005 const ListValue
& args
,
1006 bool requires_incognito_access
,
1007 const GURL
& event_url
) {
1008 RendererExtensionBindings::Invoke(
1009 function_name
, args
, NULL
, requires_incognito_access
, event_url
);
1011 // Reset the idle handler each time there's any activity like event or message
1012 // dispatch, for which Invoke is the chokepoint.
1013 if (is_extension_process_
)
1014 ScheduleIdleHandler(kInitialExtensionIdleHandlerDelayS
);
1017 void RenderThread::OnPurgeMemory() {
1018 spellchecker_
.reset(new SpellCheck());
1020 EnsureWebKitInitialized();
1022 // Clear the object cache (as much as possible; some live objects cannot be
1026 // Clear the font/glyph cache.
1027 WebFontCache::clear();
1029 // Clear the Cross-Origin Preflight cache.
1030 WebCrossOriginPreflightResultCache::clear();
1032 // Release all freeable memory from the SQLite process-global page cache (a
1033 // low-level object which backs the Connection-specific page caches).
1034 while (sqlite3_release_memory(std::numeric_limits
<int>::max()) > 0) {
1037 // Repeatedly call the V8 idle notification until it returns true ("nothing
1038 // more to free"). Note that it makes more sense to do this than to implement
1039 // a new "delete everything" pass because object references make it difficult
1040 // to free everything possible in just one pass.
1041 while (!v8::V8::IdleNotification()) {
1044 #if (defined(OS_WIN) || defined(OS_LINUX)) && defined(USE_TCMALLOC)
1045 // Tell tcmalloc to release any free pages it's still holding.
1046 MallocExtension::instance()->ReleaseFreeMemory();
1050 void RenderThread::OnPurgePluginListCache(bool reload_pages
) {
1051 EnsureWebKitInitialized();
1052 // The call below will cause a GetPlugins call with refresh=true, but at this
1053 // point we already know that the browser has refreshed its list, so disable
1054 // refresh temporarily to prevent each renderer process causing the list to be
1056 plugin_refresh_allowed_
= false;
1057 WebKit::resetPluginCache(reload_pages
);
1058 plugin_refresh_allowed_
= true;
1061 void RenderThread::OnInitSpellChecker(
1062 IPC::PlatformFileForTransit bdict_file
,
1063 const std::vector
<std::string
>& custom_words
,
1064 const std::string
& language
,
1065 bool auto_spell_correct
) {
1066 spellchecker_
->Init(IPC::PlatformFileForTransitToPlatformFile(bdict_file
),
1067 custom_words
, language
);
1068 spellchecker_
->EnableAutoSpellCorrect(auto_spell_correct
);
1071 void RenderThread::OnSpellCheckWordAdded(const std::string
& word
) {
1072 spellchecker_
->WordAdded(word
);
1075 void RenderThread::OnSpellCheckEnableAutoSpellCorrect(bool enable
) {
1076 spellchecker_
->EnableAutoSpellCorrect(enable
);
1079 void RenderThread::OnSetIsIncognitoProcess(bool is_incognito_process
) {
1080 is_incognito_process_
= is_incognito_process
;
1083 void RenderThread::OnGpuChannelEstablished(
1084 const IPC::ChannelHandle
& channel_handle
, const GPUInfo
& gpu_info
) {
1085 #if defined(OS_POSIX)
1086 // If we received a ChannelHandle, register it now.
1087 if (channel_handle
.socket
.fd
>= 0)
1088 IPC::AddChannelSocket(channel_handle
.name
, channel_handle
.socket
.fd
);
1091 gpu_channel_
->set_gpu_info(gpu_info
);
1093 if (channel_handle
.name
.size() != 0) {
1094 // Connect to the GPU process if a channel name was received.
1095 gpu_channel_
->Connect(channel_handle
.name
);
1097 // Otherwise cancel the connection.
1098 gpu_channel_
= NULL
;
1102 scoped_refptr
<base::MessageLoopProxy
>
1103 RenderThread::GetFileThreadMessageLoopProxy() {
1104 DCHECK(message_loop() == MessageLoop::current());
1105 if (!file_thread_
.get()) {
1106 file_thread_
.reset(new base::Thread("Renderer::FILE"));
1107 file_thread_
->Start();
1109 return file_thread_
->message_loop_proxy();