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 // Represents the browser side of the browser <--> renderer communication
6 // channel. There will be one RenderProcessHost per renderer process.
8 #include "chrome/browser/renderer_host/browser_render_process_host.h"
15 #include <utility> // for pair<>
18 #include "app/app_switches.h"
19 #include "base/command_line.h"
20 #include "base/field_trial.h"
21 #include "base/histogram.h"
22 #include "base/logging.h"
23 #include "base/stl_util-inl.h"
24 #include "base/string_util.h"
25 #include "base/thread.h"
26 #include "chrome/browser/browser_child_process_host.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/child_process_security_policy.h"
29 #include "chrome/browser/extensions/extension_function_dispatcher.h"
30 #include "chrome/browser/extensions/extension_message_service.h"
31 #include "chrome/browser/extensions/extensions_service.h"
32 #include "chrome/browser/extensions/user_script_master.h"
33 #include "chrome/browser/gpu_process_host.h"
34 #include "chrome/browser/history/history.h"
35 #include "chrome/browser/io_thread.h"
36 #include "chrome/browser/plugin_service.h"
37 #include "chrome/browser/profile.h"
38 #include "chrome/browser/renderer_host/audio_renderer_host.h"
39 #include "chrome/browser/renderer_host/render_view_host.h"
40 #include "chrome/browser/renderer_host/render_view_host_delegate.h"
41 #include "chrome/browser/renderer_host/render_widget_helper.h"
42 #include "chrome/browser/renderer_host/render_widget_host.h"
43 #include "chrome/browser/renderer_host/resource_message_filter.h"
44 #include "chrome/browser/renderer_host/web_cache_manager.h"
45 #include "chrome/browser/spellcheck_host.h"
46 #include "chrome/browser/visitedlink_master.h"
47 #include "chrome/common/chrome_switches.h"
48 #include "chrome/common/child_process_info.h"
49 #include "chrome/common/gpu_messages.h"
50 #include "chrome/common/logging_chrome.h"
51 #include "chrome/common/net/url_request_context_getter.h"
52 #include "chrome/common/notification_service.h"
53 #include "chrome/common/pref_names.h"
54 #include "chrome/common/process_watcher.h"
55 #include "chrome/common/render_messages.h"
56 #include "chrome/common/render_messages_params.h"
57 #include "chrome/common/result_codes.h"
58 #include "chrome/renderer/render_process_impl.h"
59 #include "chrome/renderer/render_thread.h"
60 #include "grit/generated_resources.h"
61 #include "ipc/ipc_logging.h"
62 #include "ipc/ipc_message.h"
63 #include "ipc/ipc_platform_file.h"
64 #include "ipc/ipc_switches.h"
65 #include "media/base/media_switches.h"
66 #include "webkit/glue/plugins/plugin_switches.h"
69 #include "app/win_util.h"
72 using WebKit::WebCache
;
74 #include "third_party/skia/include/core/SkBitmap.h"
77 // This class creates the IO thread for the renderer when running in
78 // single-process mode. It's not used in multi-process mode.
79 class RendererMainThread
: public base::Thread
{
81 explicit RendererMainThread(const std::string
& channel_id
)
82 : base::Thread("Chrome_InProcRendererThread"),
83 channel_id_(channel_id
),
84 render_process_(NULL
) {
87 ~RendererMainThread() {
97 render_process_
= new RenderProcessImpl();
98 render_process_
->set_main_thread(new RenderThread(channel_id_
));
99 // It's a little lame to manually set this flag. But the single process
100 // RendererThread will receive the WM_QUIT. We don't need to assert on
101 // this thread, so just force the flag manually.
102 // If we want to avoid this, we could create the InProcRendererThread
103 // directly with _beginthreadex() rather than using the Thread class.
104 base::Thread::SetThreadWasQuitProperly(true);
107 virtual void CleanUp() {
108 delete render_process_
;
116 std::string channel_id_
;
117 // Deleted in CleanUp() on the renderer thread, so don't use a smart pointer.
118 RenderProcess
* render_process_
;
122 // Size of the buffer after which individual link updates deemed not warranted
123 // and the overall update should be used instead.
124 static const unsigned kVisitedLinkBufferThreshold
= 50;
126 // This class manages buffering and sending visited link hashes (fingerprints)
127 // to renderer based on widget visibility.
128 // As opposed to the VisitedLinkEventListener in profile.cc, which coalesces to
129 // reduce the rate of messages being sent to render processes, this class
130 // ensures that the updates occur only when explicitly requested. This is
131 // used by BrowserRenderProcessHost to only send Add/Reset link events to the
132 // renderers when their tabs are visible and the corresponding RenderViews are
134 class VisitedLinkUpdater
{
136 VisitedLinkUpdater() : reset_needed_(false), has_receiver_(false) {}
138 // Buffers |links| to update, but doesn't actually relay them.
139 void AddLinks(const VisitedLinkCommon::Fingerprints
& links
) {
143 if (pending_
.size() + links
.size() > kVisitedLinkBufferThreshold
) {
144 // Once the threshold is reached, there's no need to store pending visited
145 // link updates -- we opt for resetting the state for all links.
150 pending_
.insert(pending_
.end(), links
.begin(), links
.end());
153 // Tells the updater that sending individual link updates is no longer
154 // necessary and the visited state for all links should be reset.
156 reset_needed_
= true;
160 // Sends visited link update messages: a list of links whose visited state
161 // changed or reset of visited state for all links.
162 void Update(IPC::Channel::Sender
* sender
) {
169 sender
->Send(new ViewMsg_VisitedLink_Reset());
170 reset_needed_
= false;
174 if (pending_
.size() == 0)
177 sender
->Send(new ViewMsg_VisitedLink_Add(pending_
));
182 // Notifies the updater that it is now safe to send visited state updates.
183 void ReceiverReady(IPC::Channel::Sender
* sender
) {
184 has_receiver_
= true;
185 // Go ahead and send whatever we already have buffered up.
192 VisitedLinkCommon::Fingerprints pending_
;
195 BrowserRenderProcessHost::BrowserRenderProcessHost(Profile
* profile
)
196 : RenderProcessHost(profile
),
199 ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_(
200 base::TimeDelta::FromSeconds(5),
201 this, &BrowserRenderProcessHost::ClearTransportDIBCache
)),
202 extension_process_(false) {
203 widget_helper_
= new RenderWidgetHelper();
205 registrar_
.Add(this, NotificationType::USER_SCRIPTS_UPDATED
,
206 Source
<Profile
>(profile
->GetOriginalProfile()));
207 registrar_
.Add(this, NotificationType::EXTENSION_LOADED
,
208 Source
<Profile
>(profile
->GetOriginalProfile()));
209 registrar_
.Add(this, NotificationType::EXTENSION_UNLOADED
,
210 Source
<Profile
>(profile
->GetOriginalProfile()));
211 registrar_
.Add(this, NotificationType::SPELLCHECK_HOST_REINITIALIZED
,
212 NotificationService::AllSources());
213 registrar_
.Add(this, NotificationType::SPELLCHECK_WORD_ADDED
,
214 NotificationService::AllSources());
215 registrar_
.Add(this, NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED
,
216 NotificationService::AllSources());
218 visited_link_updater_
.reset(new VisitedLinkUpdater());
220 WebCacheManager::GetInstance()->Add(id());
221 ChildProcessSecurityPolicy::GetInstance()->Add(id());
223 // Note: When we create the BrowserRenderProcessHost, it's technically
224 // backgrounded, because it has no visible listeners. But the process
225 // doesn't actually exist yet, so we'll Background it later, after
229 BrowserRenderProcessHost::~BrowserRenderProcessHost() {
230 WebCacheManager::GetInstance()->Remove(id());
231 ChildProcessSecurityPolicy::GetInstance()->Remove(id());
233 // We may have some unsent messages at this point, but that's OK.
235 while (!queued_messages_
.empty()) {
236 delete queued_messages_
.front();
237 queued_messages_
.pop();
240 // Destroy the AudioRendererHost properly.
241 if (audio_renderer_host_
.get())
242 audio_renderer_host_
->Destroy();
244 ClearTransportDIBCache();
247 bool BrowserRenderProcessHost::Init(bool is_extensions_process
) {
248 // calling Init() more than once does nothing, this makes it more convenient
249 // for the view host which may not be sure in some cases
253 // It is possible for an extension process to be reused for non-extension
254 // content, e.g. if an extension calls window.open.
255 extension_process_
= extension_process_
|| is_extensions_process
;
257 // run the IPC channel on the shared IO thread.
258 base::Thread
* io_thread
= g_browser_process
->io_thread();
260 // Construct the AudioRendererHost with the IO thread.
261 audio_renderer_host_
= new AudioRendererHost();
263 scoped_refptr
<ResourceMessageFilter
> resource_message_filter
=
264 new ResourceMessageFilter(g_browser_process
->resource_dispatcher_host(),
266 audio_renderer_host_
.get(),
267 PluginService::GetInstance(),
268 g_browser_process
->print_job_manager(),
272 CommandLine::StringType renderer_prefix
;
273 #if defined(OS_POSIX)
274 // A command prefix is something prepended to the command line of the spawned
275 // process. It is supported only on POSIX systems.
276 const CommandLine
& browser_command_line
= *CommandLine::ForCurrentProcess();
278 browser_command_line
.GetSwitchValueNative(switches::kRendererCmdPrefix
);
279 #endif // defined(OS_POSIX)
281 // Find the renderer before creating the channel so if this fails early we
282 // return without creating the channel.
283 FilePath renderer_path
=
284 ChildProcessHost::GetChildPath(renderer_prefix
.empty());
285 if (renderer_path
.empty())
288 // Setup the IPC channel.
289 const std::string channel_id
=
290 ChildProcessInfo::GenerateRandomChannelID(this);
292 new IPC::SyncChannel(channel_id
, IPC::Channel::MODE_SERVER
, this,
293 resource_message_filter
,
294 io_thread
->message_loop(), true,
295 g_browser_process
->shutdown_event()));
296 // As a preventive mesure, we DCHECK if someone sends a synchronous message
297 // with no time-out, which in the context of the browser process we should not
299 channel_
->set_sync_messages_with_no_timeout_allowed(false);
301 if (run_renderer_in_process()) {
302 // Crank up a thread and run the initialization there. With the way that
303 // messages flow between the browser and renderer, this thread is required
304 // to prevent a deadlock in single-process mode. Since the primordial
305 // thread in the renderer process runs the WebKit code and can sometimes
306 // make blocking calls to the UI thread (i.e. this thread), they need to run
307 // on separate threads.
308 in_process_renderer_
.reset(new RendererMainThread(channel_id
));
310 base::Thread::Options options
;
311 #if !defined(TOOLKIT_USES_GTK)
312 // In-process plugins require this to be a UI message loop.
313 options
.message_loop_type
= MessageLoop::TYPE_UI
;
315 // We can't have multiple UI loops on GTK, so we don't support
316 // in-process plugins.
317 options
.message_loop_type
= MessageLoop::TYPE_DEFAULT
;
319 in_process_renderer_
->StartWithOptions(options
);
321 OnProcessLaunched(); // Fake a callback that the process is ready.
323 // Build command line for renderer. We call AppendRendererCommandLine()
324 // first so the process type argument will appear first.
325 CommandLine
* cmd_line
= new CommandLine(renderer_path
);
326 if (!renderer_prefix
.empty())
327 cmd_line
->PrependWrapper(renderer_prefix
);
328 AppendRendererCommandLine(cmd_line
);
329 cmd_line
->AppendSwitchASCII(switches::kProcessChannelID
, channel_id
);
331 // Spawn the child process asynchronously to avoid blocking the UI thread.
332 // As long as there's no renderer prefix, we can use the zygote process
334 child_process_
.reset(new ChildProcessLauncher(
338 renderer_prefix
.empty(),
339 base::environment_vector(),
340 channel_
->GetClientFileDescriptor(),
345 fast_shutdown_started_
= false;
351 int BrowserRenderProcessHost::GetNextRoutingID() {
352 return widget_helper_
->GetNextRoutingID();
355 void BrowserRenderProcessHost::CancelResourceRequests(int render_widget_id
) {
356 widget_helper_
->CancelResourceRequests(render_widget_id
);
359 void BrowserRenderProcessHost::CrossSiteClosePageACK(
360 const ViewMsg_ClosePage_Params
& params
) {
361 widget_helper_
->CrossSiteClosePageACK(params
);
364 bool BrowserRenderProcessHost::WaitForUpdateMsg(
365 int render_widget_id
,
366 const base::TimeDelta
& max_delay
,
368 // The post task to this thread with the process id could be in queue, and we
369 // don't want to dispatch a message before then since it will need the handle.
370 if (child_process_
.get() && child_process_
->IsStarting())
373 return widget_helper_
->WaitForUpdateMsg(render_widget_id
, max_delay
, msg
);
376 void BrowserRenderProcessHost::ReceivedBadMessage(uint32 msg_type
) {
377 BadMessageTerminateProcess(msg_type
, GetHandle());
380 void BrowserRenderProcessHost::ViewCreated() {
381 visited_link_updater_
->ReceiverReady(this);
384 void BrowserRenderProcessHost::WidgetRestored() {
385 // Verify we were properly backgrounded.
386 DCHECK_EQ(backgrounded_
, (visible_widgets_
== 0));
388 visited_link_updater_
->Update(this);
389 SetBackgrounded(false);
392 void BrowserRenderProcessHost::WidgetHidden() {
393 // On startup, the browser will call Hide
397 DCHECK_EQ(backgrounded_
, (visible_widgets_
== 0));
399 DCHECK_GE(visible_widgets_
, 0);
400 if (visible_widgets_
== 0) {
401 DCHECK(!backgrounded_
);
402 SetBackgrounded(true);
406 void BrowserRenderProcessHost::SendVisitedLinkTable(
407 base::SharedMemory
* table_memory
) {
408 // Check if the process is still starting and we don't have a handle for it
409 // yet, in which case this will happen later when InitVisitedLinks is called.
410 if (!run_renderer_in_process() &&
411 (!child_process_
.get() || child_process_
->IsStarting())) {
415 base::SharedMemoryHandle handle_for_process
;
416 table_memory
->ShareToProcess(GetHandle(), &handle_for_process
);
417 if (base::SharedMemory::IsHandleValid(handle_for_process
))
418 Send(new ViewMsg_VisitedLink_NewTable(handle_for_process
));
421 void BrowserRenderProcessHost::AddVisitedLinks(
422 const VisitedLinkCommon::Fingerprints
& links
) {
423 visited_link_updater_
->AddLinks(links
);
424 if (visible_widgets_
== 0)
427 visited_link_updater_
->Update(this);
430 void BrowserRenderProcessHost::ResetVisitedLinks() {
431 visited_link_updater_
->AddReset();
432 if (visible_widgets_
== 0)
435 visited_link_updater_
->Update(this);
438 void BrowserRenderProcessHost::AppendRendererCommandLine(
439 CommandLine
* command_line
) const {
440 // Pass the process type first, so it shows first in process listings.
441 // Extensions use a special pseudo-process type to make them distinguishable,
442 // even though they're just renderers.
443 command_line
->AppendSwitchASCII(switches::kProcessType
,
444 extension_process_
? switches::kExtensionProcess
:
445 switches::kRendererProcess
);
447 if (logging::DialogsAreSuppressed())
448 command_line
->AppendSwitch(switches::kNoErrorDialogs
);
450 // Now send any options from our own command line we want to propogate.
451 const CommandLine
& browser_command_line
= *CommandLine::ForCurrentProcess();
452 PropagateBrowserCommandLineToRenderer(browser_command_line
, command_line
);
454 // Pass on the browser locale.
455 const std::string locale
= g_browser_process
->GetApplicationLocale();
456 command_line
->AppendSwitchASCII(switches::kLang
, locale
);
458 // If we run FieldTrials, we want to pass to their state to the renderer so
459 // that it can act in accordance with each state, or record histograms
460 // relating to the FieldTrial states.
461 std::string field_trial_states
;
462 FieldTrialList::StatesToString(&field_trial_states
);
463 if (!field_trial_states
.empty()) {
464 command_line
->AppendSwitchASCII(switches::kForceFieldTestNameAndValue
,
468 BrowserChildProcessHost::SetCrashReporterCommandLine(command_line
);
470 FilePath user_data_dir
=
471 browser_command_line
.GetSwitchValuePath(switches::kUserDataDir
);
472 if (!user_data_dir
.empty())
473 command_line
->AppendSwitchPath(switches::kUserDataDir
, user_data_dir
);
474 #if defined(OS_CHROMEOS)
475 const std::string
& profile
=
476 browser_command_line
.GetSwitchValueASCII(switches::kLoginProfile
);
477 if (!profile
.empty())
478 command_line
->AppendSwitchASCII(switches::kLoginProfile
, profile
);
482 void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
483 const CommandLine
& browser_cmd
,
484 CommandLine
* renderer_cmd
) const {
485 // Propagate the following switches to the renderer command line (along
486 // with any associated values) if present in the browser command line.
487 static const char* const kSwitchNames
[] = {
488 switches::kRendererAssertTest
,
489 #if !defined(OFFICIAL_BUILD)
490 switches::kRendererCheckFalseTest
,
491 #endif // !defined(OFFICIAL_BUILD)
492 switches::kRendererCrashTest
,
493 switches::kRendererStartupDialog
,
494 switches::kNoSandbox
,
495 switches::kTestSandbox
,
496 #if defined(USE_SECCOMP_SANDBOX)
497 switches::kDisableSeccompSandbox
,
499 switches::kEnableSeccompSandbox
,
501 #if !defined (GOOGLE_CHROME_BUILD)
502 // These are unsupported and not fully tested modes, so don't enable them
503 // for official Google Chrome builds.
504 switches::kInProcessPlugins
,
505 #endif // GOOGLE_CHROME_BUILD
506 switches::kAllowScriptingGallery
,
507 switches::kDomAutomationController
,
508 switches::kUserAgent
,
509 switches::kNoReferrers
,
510 switches::kJavaScriptFlags
,
511 switches::kRecordMode
,
512 switches::kPlaybackMode
,
513 switches::kNoJsRandomness
,
514 switches::kDisableBreakpad
,
515 switches::kFullMemoryCrashReport
,
516 switches::kEnableLogging
,
517 switches::kDumpHistogramsOnExit
,
518 switches::kDisableLogging
,
519 switches::kLoggingLevel
,
520 switches::kDebugPrint
,
521 switches::kMemoryProfiling
,
522 switches::kEnableWatchdog
,
523 switches::kMessageLoopHistogrammer
,
524 switches::kEnableDCHECK
,
525 switches::kSilentDumpOnDCHECK
,
526 switches::kUseLowFragHeapCrt
,
527 switches::kEnableSearchProviderApiV2
,
528 switches::kEnableStatsTable
,
529 switches::kExperimentalSpellcheckerFeatures
,
530 switches::kDisableAudio
,
531 switches::kSimpleDataSource
,
532 switches::kEnableBenchmarking
,
533 switches::kInternalNaCl
,
534 switches::kInternalPepper
,
535 switches::kRegisterPepperPlugins
,
536 switches::kDisableByteRangeSupport
,
537 switches::kDisableDatabases
,
538 switches::kDisableDesktopNotifications
,
539 switches::kDisableWebSockets
,
540 switches::kDisableLocalStorage
,
541 switches::kDisableSessionStorage
,
542 switches::kDisableSharedWorkers
,
543 switches::kDisableApplicationCache
,
544 switches::kDisableDeviceOrientation
,
545 switches::kEnableIndexedDatabase
,
546 switches::kDisableSpeechInput
,
547 switches::kEnableSpeechInput
,
548 switches::kDisableGeolocation
,
549 switches::kShowPaintRects
,
550 switches::kEnableOpenMax
,
551 switches::kVideoThreads
,
552 switches::kEnableVideoFullscreen
,
553 switches::kEnableVideoLayering
,
554 switches::kEnableVideoLogging
,
555 switches::kEnableTouch
,
556 // We propagate the Chrome Frame command line here as well in case the
557 // renderer is not run in the sandbox.
558 switches::kChromeFrame
,
559 // We need to propagate this flag to determine whether to make the
560 // WebGLArray constructors on the DOMWindow visible. This
561 // information is needed very early during bringup. We prefer to
562 // use the WebPreferences to set this flag on a page-by-page basis.
563 switches::kDisableExperimentalWebGL
,
564 switches::kDisableGLSLTranslator
,
565 switches::kInProcessWebGL
,
566 switches::kDisableAcceleratedCompositing
,
567 #if defined(OS_MACOSX)
568 // Allow this to be set when invoking the browser and relayed along.
569 switches::kEnableSandboxLogging
,
570 switches::kDisableFlashCoreAnimation
,
572 switches::kRemoteShellPort
,
573 switches::kEnablePepperTesting
,
574 switches::kBlockNonSandboxedPlugins
,
575 switches::kDisableOutdatedPlugins
,
576 switches::kEnableRemoting
,
577 switches::kDisableClickToPlay
,
578 switches::kEnableResourceContentSettings
,
579 switches::kPrelaunchGpuProcess
,
580 switches::kEnableAcceleratedDecoding
,
581 switches::kEnableFileSystem
,
583 renderer_cmd
->CopySwitchesFrom(browser_cmd
, kSwitchNames
,
584 arraysize(kSwitchNames
));
586 // Disable databases in incognito mode.
587 if (profile()->IsOffTheRecord() &&
588 !browser_cmd
.HasSwitch(switches::kDisableDatabases
)) {
589 renderer_cmd
->AppendSwitch(switches::kDisableDatabases
);
593 base::ProcessHandle
BrowserRenderProcessHost::GetHandle() {
594 // child_process_ is null either because we're in single process mode, we have
595 // done fast termination, or the process has crashed.
596 if (run_renderer_in_process() || !child_process_
.get())
597 return base::Process::Current().handle();
599 if (child_process_
->IsStarting())
600 return base::kNullProcessHandle
;
602 return child_process_
->GetHandle();
605 void BrowserRenderProcessHost::InitVisitedLinks() {
606 VisitedLinkMaster
* visitedlink_master
= profile()->GetVisitedLinkMaster();
607 if (!visitedlink_master
)
610 SendVisitedLinkTable(visitedlink_master
->shared_memory());
613 void BrowserRenderProcessHost::InitUserScripts() {
614 UserScriptMaster
* user_script_master
= profile()->GetUserScriptMaster();
616 // Incognito profiles won't have user scripts.
617 if (!user_script_master
)
620 if (!user_script_master
->ScriptsReady()) {
621 // No scripts ready. :(
625 // Update the renderer process with the current scripts.
626 SendUserScriptsUpdate(user_script_master
->GetSharedMemory());
629 void BrowserRenderProcessHost::InitExtensions() {
630 // TODO(aa): Should only bother sending these function names if this is an
631 // extension process.
632 std::vector
<std::string
> function_names
;
633 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names
);
634 Send(new ViewMsg_Extension_SetFunctionNames(function_names
));
637 void BrowserRenderProcessHost::SendUserScriptsUpdate(
638 base::SharedMemory
*shared_memory
) {
639 // Process is being started asynchronously. We'll end up calling
640 // InitUserScripts when it's created which will call this again.
641 if (child_process_
.get() && child_process_
->IsStarting())
644 base::SharedMemoryHandle handle_for_process
;
645 if (!shared_memory
->ShareToProcess(GetHandle(), &handle_for_process
)) {
646 // This can legitimately fail if the renderer asserts at startup.
650 if (base::SharedMemory::IsHandleValid(handle_for_process
)) {
651 Send(new ViewMsg_UserScripts_UpdatedScripts(handle_for_process
));
655 void BrowserRenderProcessHost::SendExtensionInfo() {
656 // Check if the process is still starting and we don't have a handle for it
657 // yet, in which case this will happen later when InitVisitedLinks is called.
658 if (!run_renderer_in_process() &&
659 (!child_process_
.get() || child_process_
->IsStarting())) {
663 ExtensionsService
* service
= profile()->GetExtensionsService();
666 ViewMsg_ExtensionsUpdated_Params params
;
667 for (size_t i
= 0; i
< service
->extensions()->size(); ++i
) {
668 Extension
* extension
= service
->extensions()->at(i
);
669 ViewMsg_ExtensionRendererInfo info
;
670 info
.id
= extension
->id();
671 info
.web_extent
= extension
->web_extent();
672 info
.name
= extension
->name();
673 info
.location
= extension
->location();
675 extension
->GetIconURLAllowLargerSize(Extension::EXTENSION_ICON_MEDIUM
);
676 params
.extensions
.push_back(info
);
679 Send(new ViewMsg_ExtensionsUpdated(params
));
682 bool BrowserRenderProcessHost::FastShutdownIfPossible() {
683 if (run_renderer_in_process())
684 return false; // Single process mode can't do fast shutdown.
686 if (!child_process_
.get() || child_process_
->IsStarting() || !GetHandle())
687 return false; // Render process hasn't started or is probably crashed.
689 // Test if there's an unload listener.
690 // NOTE: It's possible that an onunload listener may be installed
691 // while we're shutting down, so there's a small race here. Given that
692 // the window is small, it's unlikely that the web page has much
693 // state that will be lost by not calling its unload handlers properly.
694 if (!sudden_termination_allowed())
697 // Check for any external tab containers, since they may still be running even
698 // though this window closed.
699 listeners_iterator
iter(ListenersIterator());
700 while (!iter
.IsAtEnd()) {
701 // NOTE: This is a bit dangerous. We know that for now, listeners are
702 // always RenderWidgetHosts. But in theory, they don't have to be.
703 const RenderWidgetHost
* widget
=
704 static_cast<const RenderWidgetHost
*>(iter
.GetCurrentValue());
706 if (widget
&& widget
->IsRenderView()) {
707 const RenderViewHost
* rvh
= static_cast<const RenderViewHost
*>(widget
);
708 if (rvh
->delegate()->IsExternalTabContainer())
715 child_process_
.reset();
716 fast_shutdown_started_
= true;
720 bool BrowserRenderProcessHost::SendWithTimeout(IPC::Message
* msg
,
722 if (!channel_
.get()) {
726 return channel_
->SendWithTimeout(msg
, timeout_ms
);
729 // This is a platform specific function for mapping a transport DIB given its id
730 TransportDIB
* BrowserRenderProcessHost::MapTransportDIB(
731 TransportDIB::Id dib_id
) {
733 // On Windows we need to duplicate the handle from the remote process
734 HANDLE section
= win_util::GetSectionFromProcess(
735 dib_id
.handle
, GetHandle(), false /* read write */);
736 return TransportDIB::Map(section
);
737 #elif defined(OS_MACOSX)
738 // On OSX, the browser allocates all DIBs and keeps a file descriptor around
740 return widget_helper_
->MapTransportDIB(dib_id
);
741 #elif defined(OS_POSIX)
742 return TransportDIB::Map(dib_id
);
743 #endif // defined(OS_POSIX)
746 TransportDIB
* BrowserRenderProcessHost::GetTransportDIB(
747 TransportDIB::Id dib_id
) {
748 const std::map
<TransportDIB::Id
, TransportDIB
*>::iterator
749 i
= cached_dibs_
.find(dib_id
);
750 if (i
!= cached_dibs_
.end()) {
751 cached_dibs_cleaner_
.Reset();
755 TransportDIB
* dib
= MapTransportDIB(dib_id
);
759 if (cached_dibs_
.size() >= MAX_MAPPED_TRANSPORT_DIBS
) {
760 // Clean a single entry from the cache
761 std::map
<TransportDIB::Id
, TransportDIB
*>::iterator smallest_iterator
;
762 size_t smallest_size
= std::numeric_limits
<size_t>::max();
764 for (std::map
<TransportDIB::Id
, TransportDIB
*>::iterator
765 i
= cached_dibs_
.begin(); i
!= cached_dibs_
.end(); ++i
) {
766 if (i
->second
->size() <= smallest_size
) {
767 smallest_iterator
= i
;
768 smallest_size
= i
->second
->size();
772 delete smallest_iterator
->second
;
773 cached_dibs_
.erase(smallest_iterator
);
776 cached_dibs_
[dib_id
] = dib
;
777 cached_dibs_cleaner_
.Reset();
781 void BrowserRenderProcessHost::ClearTransportDIBCache() {
782 STLDeleteContainerPairSecondPointers(
783 cached_dibs_
.begin(), cached_dibs_
.end());
784 cached_dibs_
.clear();
787 bool BrowserRenderProcessHost::Send(IPC::Message
* msg
) {
788 if (!channel_
.get()) {
793 if (child_process_
.get() && child_process_
->IsStarting()) {
794 queued_messages_
.push(msg
);
798 return channel_
->Send(msg
);
801 void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message
& msg
) {
802 mark_child_process_activity_time();
803 if (msg
.routing_id() == MSG_ROUTING_CONTROL
) {
804 // Dispatch control messages.
805 bool msg_is_ok
= true;
806 IPC_BEGIN_MESSAGE_MAP_EX(BrowserRenderProcessHost
, msg
, msg_is_ok
)
807 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdatedCacheStats
,
809 IPC_MESSAGE_HANDLER(ViewHostMsg_SuddenTerminationChanged
,
810 SuddenTerminationChanged
);
811 IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionAddListener
,
812 OnExtensionAddListener
)
813 IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionRemoveListener
,
814 OnExtensionRemoveListener
)
815 IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionCloseChannel
,
816 OnExtensionCloseChannel
)
817 IPC_MESSAGE_HANDLER(ViewHostMsg_SpellChecker_RequestDictionary
,
818 OnSpellCheckerRequestDictionary
)
819 IPC_MESSAGE_UNHANDLED_ERROR()
820 IPC_END_MESSAGE_MAP_EX()
823 // The message had a handler, but its de-serialization failed.
824 // We consider this a capital crime. Kill the renderer if we have one.
825 ReceivedBadMessage(msg
.type());
830 // Dispatch incoming messages to the appropriate RenderView/WidgetHost.
831 IPC::Channel::Listener
* listener
= GetListenerByID(msg
.routing_id());
834 // The listener has gone away, so we must respond or else the caller will
835 // hang waiting for a reply.
836 IPC::Message
* reply
= IPC::SyncMessage::GenerateReply(&msg
);
837 reply
->set_reply_error();
842 listener
->OnMessageReceived(msg
);
845 void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid
) {
846 #if defined(IPC_MESSAGE_LOG_ENABLED)
847 Send(new ViewMsg_SetIPCLoggingEnabled(IPC::Logging::current()->Enabled()));
851 // Static. This function can be called from any thread.
852 void BrowserRenderProcessHost::BadMessageTerminateProcess(
853 uint32 msg_type
, base::ProcessHandle process
) {
854 LOG(ERROR
) << "bad message " << msg_type
<< " terminating renderer.";
855 if (run_renderer_in_process()) {
856 // In single process mode it is better if we don't suicide but just crash.
860 base::KillProcess(process
, ResultCodes::KILLED_BAD_MESSAGE
, false);
863 void BrowserRenderProcessHost::OnChannelError() {
864 // Our child process has died. If we didn't expect it, it's a crash.
865 // In any case, we need to let everyone know it's gone.
866 // The OnChannelError notification can fire multiple times due to nested sync
867 // calls to a renderer. If we don't have a valid channel here it means we
868 // already handled the error.
872 // NULL in single process mode or if fast termination happened.
874 child_process_
.get() ? child_process_
->DidProcessCrash() : false;
877 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
878 extension_process_
? 2 : 1);
881 RendererClosedDetails
details(did_crash
, extension_process_
);
882 NotificationService::current()->Notify(
883 NotificationType::RENDERER_PROCESS_CLOSED
,
884 Source
<RenderProcessHost
>(this),
885 Details
<RendererClosedDetails
>(&details
));
887 WebCacheManager::GetInstance()->Remove(id());
888 child_process_
.reset();
891 IDMap
<IPC::Channel::Listener
>::iterator
iter(&listeners_
);
892 while (!iter
.IsAtEnd()) {
893 iter
.GetCurrentValue()->OnMessageReceived(
894 ViewHostMsg_RenderViewGone(iter
.GetCurrentKey()));
898 ClearTransportDIBCache();
900 // this object is not deleted at this point and may be reused later.
901 // TODO(darin): clean this up
904 void BrowserRenderProcessHost::OnUpdatedCacheStats(
905 const WebCache::UsageStats
& stats
) {
906 WebCacheManager::GetInstance()->ObserveStats(id(), stats
);
909 void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled
) {
910 set_sudden_termination_allowed(enabled
);
913 void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded
) {
914 // Note: we always set the backgrounded_ value. If the process is NULL
915 // (and hence hasn't been created yet), we will set the process priority
916 // later when we create the process.
917 backgrounded_
= backgrounded
;
918 if (!child_process_
.get() || child_process_
->IsStarting())
922 // The cbstext.dll loads as a global GetMessage hook in the browser process
923 // and intercepts/unintercepts the kernel32 API SetPriorityClass in a
924 // background thread. If the UI thread invokes this API just when it is
925 // intercepted the stack is messed up on return from the interceptor
926 // which causes random crashes in the browser process. Our hack for now
927 // is to not invoke the SetPriorityClass API if the dll is loaded.
928 if (GetModuleHandle(L
"cbstext.dll"))
932 child_process_
->SetProcessBackgrounded(backgrounded
);
935 void BrowserRenderProcessHost::Observe(NotificationType type
,
936 const NotificationSource
& source
,
937 const NotificationDetails
& details
) {
938 switch (type
.value
) {
939 case NotificationType::USER_SCRIPTS_UPDATED
: {
940 base::SharedMemory
* shared_memory
=
941 Details
<base::SharedMemory
>(details
).ptr();
943 SendUserScriptsUpdate(shared_memory
);
947 case NotificationType::EXTENSION_LOADED
:
948 case NotificationType::EXTENSION_UNLOADED
: {
952 case NotificationType::SPELLCHECK_HOST_REINITIALIZED
: {
956 case NotificationType::SPELLCHECK_WORD_ADDED
: {
958 reinterpret_cast<const Source
<SpellCheckHost
>*>(&source
)->
959 ptr()->last_added_word());
962 case NotificationType::SPELLCHECK_AUTOSPELL_TOGGLED
: {
963 PrefService
* prefs
= profile()->GetPrefs();
964 EnableAutoSpellCorrect(
965 prefs
->GetBoolean(prefs::kEnableAutoSpellCorrect
));
975 void BrowserRenderProcessHost::OnProcessLaunched() {
976 // At this point, we used to set the process priority if it were marked as
977 // backgrounded_. We don't do that anymore because when we create a process,
978 // we really don't know how it will be used. If it is backgrounded, and not
979 // yet processed, a stray hung-cpu process (not chrome) can cause pages to
980 // not load at all. (see http://crbug.com/21884).
981 // If we could perfectly track when a process is created as visible or not,
982 // we could potentially call SetBackgrounded() properly at this point. But
983 // there are many cases, and no effective way to automate those cases.
984 // I'm choosing correctness over the feature of de-prioritizing this work.
986 Send(new ViewMsg_SetIsIncognitoProcess(profile()->IsOffTheRecord()));
993 // We don't want to initialize the spellchecker unless SpellCheckHost has been
994 // created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL
995 // then the spellchecker has been turned off, but here, we don't know if
996 // it's been turned off or just not loaded yet.
997 if (profile()->GetSpellCheckHost())
1000 if (max_page_id_
!= -1)
1001 Send(new ViewMsg_SetNextPageID(max_page_id_
+ 1));
1003 while (!queued_messages_
.empty()) {
1004 Send(queued_messages_
.front());
1005 queued_messages_
.pop();
1008 NotificationService::current()->Notify(
1009 NotificationType::RENDERER_PROCESS_CREATED
,
1010 Source
<RenderProcessHost
>(this), NotificationService::NoDetails());
1013 void BrowserRenderProcessHost::OnExtensionAddListener(
1014 const std::string
& event_name
) {
1015 if (profile()->GetExtensionMessageService()) {
1016 profile()->GetExtensionMessageService()->AddEventListener(
1021 void BrowserRenderProcessHost::OnExtensionRemoveListener(
1022 const std::string
& event_name
) {
1023 if (profile()->GetExtensionMessageService()) {
1024 profile()->GetExtensionMessageService()->RemoveEventListener(
1029 void BrowserRenderProcessHost::OnExtensionCloseChannel(int port_id
) {
1030 if (profile()->GetExtensionMessageService()) {
1031 profile()->GetExtensionMessageService()->CloseChannel(port_id
);
1035 void BrowserRenderProcessHost::OnSpellCheckerRequestDictionary() {
1036 if (profile()->GetSpellCheckHost()) {
1037 // The spellchecker initialization already started and finished; just send
1038 // it to the renderer.
1041 // We may have gotten multiple requests from different renderers. We don't
1042 // want to initialize multiple times in this case, so we set |force| to
1044 profile()->ReinitializeSpellCheckHost(false);
1048 void BrowserRenderProcessHost::AddSpellCheckWord(const std::string
& word
) {
1049 Send(new ViewMsg_SpellChecker_WordAdded(word
));
1052 void BrowserRenderProcessHost::InitSpellChecker() {
1053 SpellCheckHost
* spellcheck_host
= profile()->GetSpellCheckHost();
1054 if (spellcheck_host
) {
1055 PrefService
* prefs
= profile()->GetPrefs();
1056 IPC::PlatformFileForTransit file
;
1058 if (spellcheck_host
->bdict_file() != base::kInvalidPlatformFileValue
) {
1059 #if defined(OS_POSIX)
1060 file
= base::FileDescriptor(spellcheck_host
->bdict_file(), false);
1061 #elif defined(OS_WIN)
1062 ::DuplicateHandle(::GetCurrentProcess(), spellcheck_host
->bdict_file(),
1063 GetHandle(), &file
, 0, false, DUPLICATE_SAME_ACCESS
);
1067 Send(new ViewMsg_SpellChecker_Init(
1069 spellcheck_host
->custom_words(),
1070 spellcheck_host
->language(),
1071 prefs
->GetBoolean(prefs::kEnableAutoSpellCorrect
)));
1073 Send(new ViewMsg_SpellChecker_Init(
1074 IPC::InvalidPlatformFileForTransit(),
1075 std::vector
<std::string
>(),
1081 void BrowserRenderProcessHost::EnableAutoSpellCorrect(bool enable
) {
1082 Send(new ViewMsg_SpellChecker_EnableAutoSpellCorrect(enable
));