diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-18 00:03:23 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-18 00:03:23 +0000 |
commit | fdb7ee3dc832589e4ee911a598d4f7fd1054e551 (patch) | |
tree | 1f436470c99e3d4f861252de87f686d8048e841b /chrome/browser | |
parent | 7d8dc6258b7c9dd771eaf509f5403b602a838388 (diff) | |
download | chromium_src-fdb7ee3dc832589e4ee911a598d4f7fd1054e551.zip chromium_src-fdb7ee3dc832589e4ee911a598d4f7fd1054e551.tar.gz chromium_src-fdb7ee3dc832589e4ee911a598d4f7fd1054e551.tar.bz2 |
Revert 32203,32204,32205 - Launch processes asynchronously so as not to block the UI thread. For now, renderer only, I'll take care of plugin/worker/utility processes in a followup change.
BUG=6844
Review URL: http://codereview.chromium.org/397002
Review URL: http://codereview.chromium.org/402033
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32238 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/child_process_launcher.cc | 238 | ||||
-rw-r--r-- | chrome/browser/child_process_launcher.h | 61 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_browsertest.cc | 14 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_host.cc | 16 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.cc | 384 | ||||
-rw-r--r-- | chrome/browser/renderer_host/browser_render_process_host.h | 34 | ||||
-rw-r--r-- | chrome/browser/renderer_host/mock_render_process_host.cc | 4 | ||||
-rw-r--r-- | chrome/browser/renderer_host/mock_render_process_host.h | 1 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_process_host.h | 8 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents.cc | 3 | ||||
-rw-r--r-- | chrome/browser/visitedlink_event_listener.cc | 10 | ||||
-rw-r--r-- | chrome/browser/visitedlink_master.cc | 13 | ||||
-rw-r--r-- | chrome/browser/visitedlink_master.h | 8 | ||||
-rw-r--r-- | chrome/browser/visitedlink_unittest.cc | 9 |
14 files changed, 329 insertions, 474 deletions
diff --git a/chrome/browser/child_process_launcher.cc b/chrome/browser/child_process_launcher.cc deleted file mode 100644 index 72cf4e5..0000000 --- a/chrome/browser/child_process_launcher.cc +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/child_process_launcher.h" - -#include "base/command_line.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/scoped_ptr.h" -#include "base/thread.h" -#include "chrome/browser/chrome_thread.h" -#include "chrome/common/chrome_descriptors.h" -#include "chrome/common/chrome_switches.h" -#include "chrome/common/process_watcher.h" -#include "chrome/common/result_codes.h" -#include "ipc/ipc_sync_channel.h" - -#if defined(OS_WIN) -#include "chrome/browser/sandbox_policy.h" -#elif defined(OS_LINUX) -#include "base/singleton.h" -#include "chrome/browser/crash_handler_host_linux.h" -#include "chrome/browser/zygote_host_linux.h" -#include "chrome/browser/renderer_host/render_sandbox_host_linux.h" -#endif - -namespace { - -class LauncherThread : public base::Thread { - public: - LauncherThread() : base::Thread("LauncherThread") { } -}; - -static base::LazyInstance<LauncherThread> launcher(base::LINKER_INITIALIZED); -} - -// Having the functionality of ChildProcessLauncher be in an internal -// ref counted object allows us to automatically terminate the process when the -// parent class destructs, while still holding on to state that we need. -class ChildProcessLauncher::Context - : public base::RefCountedThreadSafe<ChildProcessLauncher::Context> { - public: - Context() : starting_(true), zygote_(false) {} - - void Launch(CommandLine* cmd_line, int ipcfd, Client* client) { - client_ = client; - - CHECK(ChromeThread::GetCurrentThreadIdentifier(&client_thread_id_)); - if (!launcher.Get().message_loop()) - launcher.Get().Start(); - - launcher.Get().message_loop()->PostTask( - FROM_HERE, - NewRunnableMethod( - this, &Context::LaunchInternal, ipcfd, cmd_line)); - } - - void ResetClient() { - // No need for locking as this function gets called on the same thread that - // client_ would be used. - CHECK(ChromeThread::CurrentlyOn(client_thread_id_)); - client_ = NULL; - } - - private: - friend class base::RefCountedThreadSafe<ChildProcessLauncher::Context>; - friend class ChildProcessLauncher; - - ~Context() { - Terminate(); - } - - void LaunchInternal(int ipcfd, CommandLine* cmd_line) { - scoped_ptr<CommandLine> cmd_line_deleter(cmd_line); - base::ProcessHandle handle; - bool zygote = false; -#if defined(OS_WIN) - handle = sandbox::StartProcess(cmd_line); -#elif defined(OS_POSIX) - -#if defined(OS_LINUX) - // On Linux, normally spawn processes with zygotes. We can't do this when - // we're spawning child processes through an external program (i.e. there is - // a command prefix) like GDB so fall through to the POSIX case then. - if (!CommandLine::ForCurrentProcess()->HasSwitch( - switches::kRendererCmdPrefix)) { - zygote = true; - - base::GlobalDescriptors::Mapping mapping; - mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd)); - const int crash_signal_fd = - Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); - if (crash_signal_fd >= 0) { - mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal, - crash_signal_fd)); - } - handle = Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping); - } -#endif - - if (!zygote) { - base::file_handle_mapping_vector fds_to_map; - fds_to_map.push_back(std::make_pair(ipcfd, kPrimaryIPCChannel + 3)); - -#if defined(OS_LINUX) - // On Linux, we need to add some extra file descriptors for crash handling - // and the sandbox. - const int crash_signal_fd = - Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); - if (crash_signal_fd >= 0) { - fds_to_map.push_back(std::make_pair(crash_signal_fd, - kCrashDumpSignal + 3)); - } - const int sandbox_fd = - Singleton<RenderSandboxHostLinux>()->GetRendererSocket(); - fds_to_map.push_back(std::make_pair(sandbox_fd, kSandboxIPCChannel + 3)); -#endif // defined(OS_LINUX) - - // Actually launch the app. - if (!base::LaunchApp(cmd_line->argv(), fds_to_map, false, &handle)) - handle = 0; - } -#endif - - ChromeThread::PostTask( - client_thread_id_, FROM_HERE, - NewRunnableMethod( - this, &ChildProcessLauncher::Context::Notify, handle, zygote)); - } - - void Notify(base::ProcessHandle handle, bool zygote) { - starting_ = false; - process_.set_handle(handle); - zygote_ = zygote; - if (client_) { - client_->OnProcessLaunched(); - } else { - Terminate(); - } - } - - void Terminate() { - if (!process_.handle()) - return; - - // On Posix, EnsureProcessTerminated can lead to 2 seconds of sleep! So - // don't this on the UI/IO threads. - launcher.Get().message_loop()->PostTask( - FROM_HERE, - NewRunnableFunction( - &ChildProcessLauncher::Context::TerminateInternal, - process_.handle(), zygote_)); - process_.set_handle(base::kNullProcessHandle); - } - - static void TerminateInternal(base::ProcessHandle handle, bool zygote) { - base::Process process(handle); - // Client has gone away, so just kill the process. Using exit code 0 - // means that UMA won't treat this as a crash. - process.Terminate(ResultCodes::NORMAL_EXIT); - // On POSIX, we must additionally reap the child. -#if defined(OS_POSIX) - if (zygote) { -#if defined(OS_LINUX) - // If the renderer was created via a zygote, we have to proxy the reaping - // through the zygote process. - Singleton<ZygoteHost>()->EnsureProcessTerminated(handle); -#endif // defined(OS_LINUX) - } else { - ProcessWatcher::EnsureProcessTerminated(handle); - } -#endif - process.Close(); - } - - Client* client_; - ChromeThread::ID client_thread_id_; - base::Process process_; - bool starting_; - bool zygote_; -}; - - -ChildProcessLauncher::ChildProcessLauncher(CommandLine* cmd_line, - IPC::SyncChannel* channel, - Client* client) { - context_ = new Context(); - - int ipcfd = 0; -#if defined(OS_POSIX) - ipcfd = channel->GetClientFileDescriptor(); -#endif - context_->Launch(cmd_line, ipcfd, client); -} - -ChildProcessLauncher::~ChildProcessLauncher() { - context_->ResetClient(); -} - -bool ChildProcessLauncher::IsStarting() { - return context_->starting_; -} - -base::ProcessHandle ChildProcessLauncher::GetHandle() { - DCHECK(!context_->starting_); - return context_->process_.handle(); -} - -bool ChildProcessLauncher::DidProcessCrash() { - bool did_crash, child_exited; - base::ProcessHandle handle = context_->process_.handle(); -#if defined(OS_LINUX) - if (context_->zygote_) { - did_crash = Singleton<ZygoteHost>()->DidProcessCrash(handle, &child_exited); - } else -#endif - { - did_crash = base::DidProcessCrash(&child_exited, handle); - } - - // POSIX: If the process crashed, then the kernel closed the socket for it - // and so the child has already died by the time we get here. Since - // DidProcessCrash called waitpid with WNOHANG, it'll reap the process. - // However, if DidProcessCrash didn't reap the child, we'll need to in - // Terminate via ProcessWatcher. So we can't close the handle here. - // - // This is moot on Windows where |child_exited| will always be true. - if (child_exited) - context_->process_.Close(); - - return did_crash; -} - -void ChildProcessLauncher::SetProcessBackgrounded(bool background) { - DCHECK(!context_->starting_); - context_->process_.SetProcessBackgrounded(background); -} diff --git a/chrome/browser/child_process_launcher.h b/chrome/browser/child_process_launcher.h deleted file mode 100644 index a2c02f3..0000000 --- a/chrome/browser/child_process_launcher.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_COMMON_CHILD_PROCESS_LAUNCHER_H_ -#define CHROME_COMMON_CHILD_PROCESS_LAUNCHER_H_ - -#include "base/basictypes.h" -#include "base/process.h" -#include "base/ref_counted.h" - -class CommandLine; - -namespace IPC { -class SyncChannel; -} - -// Launches a process asynchronously and notifies the client of the process -// handle when it's available. It's used to avoid blocking the calling thread -// on the OS since often it can take > 100 ms to create the process. -class ChildProcessLauncher { - public: - class Client { - public: - // Will be called on the thread that the ChildProcessLauncher was - // constructed on. - virtual void OnProcessLaunched() = 0; - }; - - // Launches the process asynchronously, calling the client when the result is - // ready. Deleting this object before the process is created is safe, since - // the callback won't be called. If the process is still running by the time - // this object destructs, it will be terminated. - // Takes ownership of cmd_line. - ChildProcessLauncher(CommandLine* cmd_line, - IPC::SyncChannel* channel, - Client* client); - ~ChildProcessLauncher(); - - // True if the process is being launched and so the handle isn't available. - bool IsStarting(); - - // Getter for the process handle. Only call after the process has started. - base::ProcessHandle GetHandle(); - - // Call this when the process exits to know if a process crashed or not. - bool DidProcessCrash(); - - // Changes whether the process runs in the background or not. Only call - // this after the process has started. - void SetProcessBackgrounded(bool background); - - private: - class Context; - - scoped_refptr<Context> context_; - - DISALLOW_COPY_AND_ASSIGN(ChildProcessLauncher); -}; - -#endif // CHROME_COMMON_CHILD_PROCESS_LAUNCHER_H_ diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc index 0fca208..1d3b5a9 100644 --- a/chrome/browser/extensions/extension_browsertest.cc +++ b/chrome/browser/extensions/extension_browsertest.cc @@ -116,10 +116,15 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension( } void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) { + NotificationRegistrar registrar; + registrar.Add(this, NotificationType::EXTENSION_LOADED, + NotificationService::AllSources()); + ExtensionsService* service = browser()->profile()->GetExtensionsService(); service->ReloadExtension(extension_id); - ui_test_utils::RegisterAndWait(NotificationType::EXTENSION_PROCESS_CREATED, - this, kTimeoutMs); + MessageLoop::current()->PostDelayedTask( + FROM_HERE, new MessageLoop::QuitTask, kTimeoutMs); + ui_test_utils::RunMessageLoop(); } void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) { @@ -254,11 +259,6 @@ void ExtensionBrowserTest::Observe(NotificationType type, MessageLoopForUI::current()->Quit(); break; - case NotificationType::EXTENSION_PROCESS_CREATED: - std::cout << "Got EXTENSION_PROCESS_CREATED notification.\n"; - MessageLoopForUI::current()->Quit(); - break; - default: NOTREACHED(); break; diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index b0771ad..85f48de5 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -124,11 +124,6 @@ ExtensionHost::ExtensionHost(Extension* extension, SiteInstance* site_instance, render_view_host_->AllowBindings(BindingsPolicy::EXTENSION); if (enable_dom_automation_) render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION); - - // Listen for when the render process' handle is available so we can add it - // to the task manager then. - registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED, - Source<RenderProcessHost>(render_process_host())); } ExtensionHost::~ExtensionHost() { @@ -180,6 +175,11 @@ void ExtensionHost::CreateRenderViewNow() { render_view_host_->CreateRenderView(profile_->GetRequestContext()); NavigateToURL(url_); DCHECK(IsRenderViewLive()); + LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; + NotificationService::current()->Notify( + NotificationType::EXTENSION_PROCESS_CREATED, + Source<Profile>(profile_), + Details<ExtensionHost>(this)); } void ExtensionHost::NavigateToURL(const GURL& url) { @@ -216,12 +216,6 @@ void ExtensionHost::Observe(NotificationType type, NavigateToURL(url_); } else if (type == NotificationType::BROWSER_THEME_CHANGED) { InsertThemeCSS(); - } else if (type == NotificationType::RENDERER_PROCESS_CREATED) { - LOG(INFO) << "Sending EXTENSION_PROCESS_CREATED"; - NotificationService::current()->Notify( - NotificationType::EXTENSION_PROCESS_CREATED, - Source<Profile>(profile_), - Details<ExtensionHost>(this)); } else { NOTREACHED(); } diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 1f630af..896b2fd 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -20,7 +20,6 @@ #include "base/field_trial.h" #include "base/logging.h" #include "base/process_util.h" -#include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/thread.h" #include "chrome/browser/browser_process.h" @@ -48,8 +47,10 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/child_process_info.h" #include "chrome/common/child_process_host.h" +#include "chrome/common/chrome_descriptors.h" #include "chrome/common/logging_chrome.h" #include "chrome/common/notification_service.h" +#include "chrome/common/process_watcher.h" #include "chrome/common/render_messages.h" #include "chrome/common/result_codes.h" #include "chrome/renderer/render_process.h" @@ -62,6 +63,12 @@ #if defined(OS_WIN) #include "app/win_util.h" +#include "chrome/browser/sandbox_policy.h" +#elif defined(OS_LINUX) +#include "base/singleton.h" +#include "chrome/browser/crash_handler_host_linux.h" +#include "chrome/browser/zygote_host_linux.h" +#include "chrome/browser/renderer_host/render_sandbox_host_linux.h" #endif using WebKit::WebCache; @@ -194,6 +201,7 @@ BrowserRenderProcessHost::BrowserRenderProcessHost(Profile* profile) ALLOW_THIS_IN_INITIALIZER_LIST(cached_dibs_cleaner_( base::TimeDelta::FromSeconds(5), this, &BrowserRenderProcessHost::ClearTransportDIBCache)), + zygote_child_(false), extension_process_(false) { widget_helper_ = new RenderWidgetHelper(); @@ -231,15 +239,21 @@ BrowserRenderProcessHost::~BrowserRenderProcessHost() { // We may have some unsent messages at this point, but that's OK. channel_.reset(); - while (!queued_messages_.empty()) { - delete queued_messages_.front(); - queued_messages_.pop(); - } // Destroy the AudioRendererHost properly. if (audio_renderer_host_.get()) audio_renderer_host_->Destroy(); + if (process_.handle() && !run_renderer_in_process()) { + if (zygote_child_) { +#if defined(OS_LINUX) + Singleton<ZygoteHost>()->EnsureProcessTerminated(process_.handle()); +#endif + } else { + ProcessWatcher::EnsureProcessTerminated(process_.handle()); + } + } + ClearTransportDIBCache(); NotificationService::current()->Notify( @@ -299,6 +313,16 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process, // be doing. channel_->set_sync_messages_with_no_timeout_allowed(false); + // Build command line for renderer, we have to quote the executable name to + // deal with spaces. + CommandLine cmd_line(renderer_path); + cmd_line.AppendSwitchWithValue(switches::kProcessChannelID, + ASCIIToWide(channel_id)); + if (is_extensions_process) + cmd_line.AppendSwitch(switches::kEnableDatabases); + bool has_cmd_prefix; + AppendRendererCommandLine(&cmd_line, &has_cmd_prefix); + if (run_renderer_in_process()) { // Crank up a thread and run the initialization there. With the way that // messages flow between the browser and renderer, this thread is required @@ -318,25 +342,49 @@ bool BrowserRenderProcessHost::Init(bool is_extensions_process, options.message_loop_type = MessageLoop::TYPE_DEFAULT; #endif in_process_renderer_->StartWithOptions(options); - - OnProcessLaunched(); // Fake a callback that the process is ready. } else { - // Build command line for renderer, we have to quote the executable name to - // deal with spaces. - scoped_ptr<CommandLine> cmd_line(new CommandLine(renderer_path)); - cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, - ASCIIToWide(channel_id)); - if (is_extensions_process) - cmd_line->AppendSwitch(switches::kEnableDatabases); - AppendRendererCommandLine(cmd_line.get()); - - // Spawn the child process asynchronously to avoid blocking the UI thread. - child_process_.reset(new ChildProcessLauncher( - cmd_line.release(), channel_.get(), this)); + base::TimeTicks begin_launch_time = base::TimeTicks::Now(); + // Actually spawn the child process. + base::ProcessHandle process = ExecuteRenderer(&cmd_line, has_cmd_prefix); + if (!process) { + channel_.reset(); + return false; + } + process_.set_handle(process); fast_shutdown_started_ = false; + + // Log the launch time, separating out the first one (which will likely be + // slower due to the rest of the browser initializing at the same time). + static bool done_first_launch = false; + if (done_first_launch) { + UMA_HISTOGRAM_TIMES("MPArch.RendererLaunchSubsequent", + base::TimeTicks::Now() - begin_launch_time); + } else { + UMA_HISTOGRAM_TIMES("MPArch.RendererLaunchFirst", + base::TimeTicks::Now() - begin_launch_time); + done_first_launch = true; + } } + // Now that the process is created, set its backgrounding accordingly. + SetBackgrounded(backgrounded_); + + InitVisitedLinks(); + InitUserScripts(); + InitExtensions(); +#if defined(SPELLCHECKER_IN_RENDERER) + // We don't want to initialize the spellchecker unless SpellCheckHost has been + // created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL + // then the spellchecker has been turned off, but here, we don't know if + // it's been turned off or just not loaded yet. + if (profile()->GetSpellCheckHost()) + InitSpellChecker(); +#endif + + if (max_page_id_ != -1) + Send(new ViewMsg_SetNextPageID(max_page_id_ + 1)); + return true; } @@ -356,16 +404,11 @@ void BrowserRenderProcessHost::CrossSiteClosePageACK( bool BrowserRenderProcessHost::WaitForPaintMsg(int render_widget_id, const base::TimeDelta& max_delay, IPC::Message* msg) { - // The post task to this thread with the process id could be in queue, and we - // don't want to dispatch a message before then since it will need the handle. - if (child_process_.get() && child_process_->IsStarting()) - return false; - return widget_helper_->WaitForPaintMsg(render_widget_id, max_delay, msg); } void BrowserRenderProcessHost::ReceivedBadMessage(uint16 msg_type) { - BadMessageTerminateProcess(msg_type, GetHandle()); + BadMessageTerminateProcess(msg_type, process_.handle()); } void BrowserRenderProcessHost::ViewCreated() { @@ -403,21 +446,6 @@ void BrowserRenderProcessHost::AddWord(const string16& word) { } } -void BrowserRenderProcessHost::SendVisitedLinkTable( - base::SharedMemory* table_memory) { - // Check if the process is still starting and we don't have a handle for it - // yet, in which case this will happen later when InitVisitedLinks is called. - if (!run_renderer_in_process() && - (!child_process_.get() || child_process_->IsStarting())) { - return; - } - - base::SharedMemoryHandle handle_for_process; - table_memory->ShareToProcess(GetHandle(), &handle_for_process); - if (base::SharedMemory::IsHandleValid(handle_for_process)) - Send(new ViewMsg_VisitedLink_NewTable(handle_for_process)); -} - void BrowserRenderProcessHost::AddVisitedLinks( const VisitedLinkCommon::Fingerprints& links) { visited_link_updater_->AddLinks(links); @@ -436,7 +464,8 @@ void BrowserRenderProcessHost::ResetVisitedLinks() { } void BrowserRenderProcessHost::AppendRendererCommandLine( - CommandLine* command_line) const { + CommandLine* command_line, + bool* has_cmd_prefix) const { if (logging::DialogsAreSuppressed()) command_line->AppendSwitch(switches::kNoErrorDialogs); @@ -468,12 +497,16 @@ void BrowserRenderProcessHost::AppendRendererCommandLine( // A command prefix is something prepended to the command line of the spawned // process. It is supported only on POSIX systems. #if defined(OS_POSIX) - if (browser_command_line.HasSwitch(switches::kRendererCmdPrefix)) { + *has_cmd_prefix = + browser_command_line.HasSwitch(switches::kRendererCmdPrefix); + if (*has_cmd_prefix) { // launch the renderer child with some prefix (usually "gdb --args") const std::wstring prefix = browser_command_line.GetSwitchValue(switches::kRendererCmdPrefix); command_line->PrependWrapper(prefix); } +#else + *has_cmd_prefix = false; #endif // defined(OS_POSIX) ChildProcessHost::SetCrashReporterCommandLine(command_line); @@ -565,26 +598,88 @@ void BrowserRenderProcessHost::PropogateBrowserCommandLineToRenderer( } } -base::ProcessHandle BrowserRenderProcessHost::GetHandle() { - // child_process_ is null either because we're in single process mode, we have - // done fast termination, or the process has crashed. - if (run_renderer_in_process() || !child_process_.get()) - return base::Process::Current().handle(); +#if defined(OS_WIN) - if (child_process_->IsStarting()) { - NOTREACHED() << "BrowserRenderProcessHost::GetHandle() called early!"; - return base::kNullProcessHandle; +base::ProcessHandle BrowserRenderProcessHost::ExecuteRenderer( + CommandLine* cmd_line, + bool has_cmd_prefix) { + return sandbox::StartProcess(cmd_line); +} + +#elif defined(OS_POSIX) + +base::ProcessHandle BrowserRenderProcessHost::ExecuteRenderer( + CommandLine* cmd_line, + bool has_cmd_prefix) { +#if defined(OS_LINUX) + // On Linux, normally spawn processes with zygotes. We can't do this when + // we're spawning child processes through an external program (i.e. there is a + // command prefix) like GDB so fall through to the POSIX case then. + if (!has_cmd_prefix) { + base::GlobalDescriptors::Mapping mapping; + const int ipcfd = channel_->GetClientFileDescriptor(); + mapping.push_back(std::pair<uint32_t, int>(kPrimaryIPCChannel, ipcfd)); + const int crash_signal_fd = + Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); + if (crash_signal_fd >= 0) { + mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal, + crash_signal_fd)); + } + zygote_child_ = true; + return Singleton<ZygoteHost>()->ForkRenderer(cmd_line->argv(), mapping); + } +#endif // defined(OS_LINUX) + + // NOTE: This code is duplicated with plugin_process_host.cc, but + // there's not a good place to de-duplicate it. + base::file_handle_mapping_vector fds_to_map; + const int ipcfd = channel_->GetClientFileDescriptor(); + fds_to_map.push_back(std::make_pair(ipcfd, kPrimaryIPCChannel + 3)); + +#if defined(OS_LINUX) + // On Linux, we need to add some extra file descriptors for crash handling and + // the sandbox. + const int crash_signal_fd = + Singleton<RendererCrashHandlerHostLinux>()->GetDeathSignalSocket(); + if (crash_signal_fd >= 0) { + fds_to_map.push_back(std::make_pair(crash_signal_fd, + kCrashDumpSignal + 3)); } + const int sandbox_fd = + Singleton<RenderSandboxHostLinux>()->GetRendererSocket(); + fds_to_map.push_back(std::make_pair(sandbox_fd, kSandboxIPCChannel + 3)); +#endif // defined(OS_LINUX) - return child_process_->GetHandle(); + // Actually launch the app. + zygote_child_ = false; + base::ProcessHandle process_handle; + if (!base::LaunchApp(cmd_line->argv(), fds_to_map, false, &process_handle)) + return 0; + return process_handle; +} + +#endif // defined(OS_POSIX) + +base::ProcessHandle BrowserRenderProcessHost::GetHandle() { + if (run_renderer_in_process()) + return base::Process::Current().handle(); + + return process_.handle(); } void BrowserRenderProcessHost::InitVisitedLinks() { VisitedLinkMaster* visitedlink_master = profile()->GetVisitedLinkMaster(); - if (!visitedlink_master) + if (!visitedlink_master) { return; + } + + base::SharedMemoryHandle handle_for_process; + bool r = visitedlink_master->ShareToProcess(GetHandle(), &handle_for_process); + DCHECK(r); - SendVisitedLinkTable(visitedlink_master->shared_memory()); + if (base::SharedMemory::IsHandleValid(handle_for_process)) { + Send(new ViewMsg_VisitedLink_NewTable(handle_for_process)); + } } void BrowserRenderProcessHost::InitUserScripts() { @@ -610,11 +705,6 @@ void BrowserRenderProcessHost::InitExtensions() { void BrowserRenderProcessHost::SendUserScriptsUpdate( base::SharedMemory *shared_memory) { - // Process is being started asynchronously. We'll end up calling - // InitUserScripts when it's created which will call this again. - if (child_process_.get() && child_process_->IsStarting()) - return; - base::SharedMemoryHandle handle_for_process; if (!shared_memory->ShareToProcess(GetHandle(), &handle_for_process)) { // This can legitimately fail if the renderer asserts at startup. @@ -627,12 +717,11 @@ void BrowserRenderProcessHost::SendUserScriptsUpdate( } bool BrowserRenderProcessHost::FastShutdownIfPossible() { + if (!process_.handle()) + return false; // Render process is probably crashed. if (run_renderer_in_process()) return false; // Single process mode can't do fast shutdown. - if (!child_process_.get() || child_process_->IsStarting() || !GetHandle()) - return false; // Render process hasn't started or is probably crashed. - // Test if there's an unload listener. // NOTE: It's possible that an onunload listener may be installed // while we're shutting down, so there's a small race here. Given that @@ -659,7 +748,23 @@ bool BrowserRenderProcessHost::FastShutdownIfPossible() { iter.Advance(); } - child_process_.reset(); + // Otherwise, we're allowed to just terminate the process. Using exit code 0 + // means that UMA won't treat this as a renderer crash. + process_.Terminate(ResultCodes::NORMAL_EXIT); + // On POSIX, we must additionally reap the child. +#if defined(OS_POSIX) + if (zygote_child_) { +#if defined(OS_LINUX) + // If the renderer was created via a zygote, we have to proxy the reaping + // through the zygote process. + Singleton<ZygoteHost>()->EnsureProcessTerminated(process_.handle()); +#endif // defined(OS_LINUX) + } else { + ProcessWatcher::EnsureProcessGetsReaped(process_.handle()); + } +#endif // defined(OS_POSIX) + process_.Close(); + fast_shutdown_started_ = true; return true; } @@ -726,8 +831,11 @@ TransportDIB* BrowserRenderProcessHost::GetTransportDIB( } void BrowserRenderProcessHost::ClearTransportDIBCache() { - STLDeleteContainerPairSecondPointers( - cached_dibs_.begin(), cached_dibs_.end()); + for (std::map<TransportDIB::Id, TransportDIB*>::iterator + i = cached_dibs_.begin(); i != cached_dibs_.end(); ++i) { + delete i->second; + } + cached_dibs_.clear(); } @@ -736,12 +844,6 @@ bool BrowserRenderProcessHost::Send(IPC::Message* msg) { delete msg; return false; } - - if (child_process_.get() && child_process_->IsStarting()) { - queued_messages_.push(msg); - return true; - } - return channel_->Send(msg); } @@ -793,8 +895,49 @@ void BrowserRenderProcessHost::OnMessageReceived(const IPC::Message& msg) { } void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) { + // process_ is not NULL if we created the renderer process + if (!process_.handle()) { + if (fast_shutdown_started_) { + // We terminated the process, but the ChannelConnected task was still + // in the queue. We can safely ignore it. + return; + } else if (base::GetCurrentProcId() == peer_pid) { + // We are in single-process mode. In theory we should have access to + // ourself but it may happen that we don't. + process_.set_handle(base::GetCurrentProcessHandle()); + } else { +#if defined(OS_WIN) + // Request MAXIMUM_ALLOWED to match the access a handle + // returned by CreateProcess() has to the process object. + process_.set_handle(OpenProcess(MAXIMUM_ALLOWED, FALSE, peer_pid)); +#else + NOTREACHED(); +#endif + DCHECK(process_.handle()); + } + } else { + // Need to verify that the peer_pid is actually the process we know, if + // it is not, we need to panic now. See bug 1002150. + if (peer_pid != process_.pid()) { + // This check is invalid on Linux for two reasons: + // a) If we are running the renderer in a wrapper (with + // --renderer-cmd-prefix) then the we'll see the PID of the wrapper + // process, not the renderer itself. + // b) If we are using the SUID sandbox with CLONE_NEWPID, then the + // renderer will be in a new PID namespace and will believe that + // it's PID is 2 or 3. + // Additionally, this check isn't a security problem on Linux since we + // don't use the PID as reported by the renderer. +#if !defined(OS_LINUX) + CHECK(peer_pid == process_.pid()) << peer_pid << " " << process_.pid(); +#endif + } + mark_child_process_activity_time(); + } + #if defined(IPC_MESSAGE_LOG_ENABLED) - Send(new ViewMsg_SetIPCLoggingEnabled(IPC::Logging::current()->Enabled())); + bool enabled = IPC::Logging::current()->Enabled(); + Send(new ViewMsg_SetIPCLoggingEnabled(enabled)); #endif } @@ -802,7 +945,7 @@ void BrowserRenderProcessHost::OnChannelConnected(int32 peer_pid) { void BrowserRenderProcessHost::BadMessageTerminateProcess( uint16 msg_type, base::ProcessHandle process) { LOG(ERROR) << "bad message " << msg_type << " terminating renderer."; - if (run_renderer_in_process()) { + if (BrowserRenderProcessHost::run_renderer_in_process()) { // In single process mode it is better if we don't suicide but just crash. CHECK(false); } @@ -819,17 +962,42 @@ void BrowserRenderProcessHost::OnChannelError() { if (!channel_.get()) return; - // NULL in single process mode or if fast termination happened. - bool did_crash = - child_process_.get() ? child_process_->DidProcessCrash() : false; + bool child_exited; + bool did_crash; + if (!process_.handle()) { + // The process has been terminated (likely FastShutdownIfPossible). + did_crash = false; + child_exited = true; + } else if (zygote_child_) { +#if defined(OS_LINUX) + did_crash = Singleton<ZygoteHost>()->DidProcessCrash( + process_.handle(), &child_exited); +#else + NOTREACHED(); + did_crash = true; +#endif + } else { + did_crash = base::DidProcessCrash(&child_exited, process_.handle()); + } NotificationService::current()->Notify( NotificationType::RENDERER_PROCESS_CLOSED, Source<RenderProcessHost>(this), Details<bool>(&did_crash)); + // POSIX: If the process crashed, then the kernel closed the socket for it + // and so the child has already died by the time we get here. Since + // DidProcessCrash called waitpid with WNOHANG, it'll reap the process. + // However, if DidProcessCrash didn't reap the child, we'll need to in + // ~BrowserRenderProcessHost via ProcessWatcher. So we can't close the handle + // here. + // + // This is moot on Windows where |child_exited| will always be true. + if (child_exited) + process_.Close(); + WebCacheManager::GetInstance()->Remove(id()); - child_process_.reset(); + channel_.reset(); IDMap<IPC::Channel::Listener>::iterator iter(&listeners_); @@ -867,27 +1035,32 @@ void BrowserRenderProcessHost::SuddenTerminationChanged(bool enabled) { } void BrowserRenderProcessHost::SetBackgrounded(bool backgrounded) { - // Note: we always set the backgrounded_ value. If the process is NULL - // (and hence hasn't been created yet), we will set the process priority - // later when we create the process. - backgrounded_ = backgrounded; - if (!child_process_.get() || child_process_->IsStarting()) - return; + // If the process_ is NULL, the process hasn't been created yet. + if (process_.handle()) { + bool should_set_backgrounded = true; #if defined(OS_WIN) - // The cbstext.dll loads as a global GetMessage hook in the browser process - // and intercepts/unintercepts the kernel32 API SetPriorityClass in a - // background thread. If the UI thread invokes this API just when it is - // intercepted the stack is messed up on return from the interceptor - // which causes random crashes in the browser process. Our hack for now - // is to not invoke the SetPriorityClass API if the dll is loaded. - if (GetModuleHandle(L"cbstext.dll")) - return; + // The cbstext.dll loads as a global GetMessage hook in the browser process + // and intercepts/unintercepts the kernel32 API SetPriorityClass in a + // background thread. If the UI thread invokes this API just when it is + // intercepted the stack is messed up on return from the interceptor + // which causes random crashes in the browser process. Our hack for now + // is to not invoke the SetPriorityClass API if the dll is loaded. + should_set_backgrounded = (GetModuleHandle(L"cbstext.dll") == NULL); #endif // OS_WIN - child_process_->SetProcessBackgrounded(backgrounded); + if (should_set_backgrounded) { + process_.SetProcessBackgrounded(backgrounded); + } + } + + // Note: we always set the backgrounded_ value. If the process is NULL + // (and hence hasn't been created yet), we will set the process priority + // later when we create the process. + backgrounded_ = backgrounded; } +// NotificationObserver implementation. void BrowserRenderProcessHost::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { @@ -930,35 +1103,6 @@ void BrowserRenderProcessHost::Observe(NotificationType type, } } -void BrowserRenderProcessHost::OnProcessLaunched() { - // Now that the process is created, set its backgrounding accordingly. - SetBackgrounded(backgrounded_); - - InitVisitedLinks(); - InitUserScripts(); - InitExtensions(); -#if defined(SPELLCHECKER_IN_RENDERER) - // We don't want to initialize the spellchecker unless SpellCheckHost has been - // created. In InitSpellChecker(), we know if GetSpellCheckHost() is NULL - // then the spellchecker has been turned off, but here, we don't know if - // it's been turned off or just not loaded yet. - if (profile()->GetSpellCheckHost()) - InitSpellChecker(); -#endif - - if (max_page_id_ != -1) - Send(new ViewMsg_SetNextPageID(max_page_id_ + 1)); - - while (!queued_messages_.empty()) { - Send(queued_messages_.front()); - queued_messages_.pop(); - } - - NotificationService::current()->Notify( - NotificationType::RENDERER_PROCESS_CREATED, - Source<RenderProcessHost>(this), NotificationService::NoDetails()); -} - void BrowserRenderProcessHost::OnExtensionAddListener( const std::string& event_name) { if (profile()->GetExtensionMessageService()) { diff --git a/chrome/browser/renderer_host/browser_render_process_host.h b/chrome/browser/renderer_host/browser_render_process_host.h index 4ab6c73..caf55d7 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.h +++ b/chrome/browser/renderer_host/browser_render_process_host.h @@ -8,7 +8,6 @@ #include "build/build_config.h" #include <map> -#include <queue> #include <string> #include "base/process.h" @@ -18,7 +17,6 @@ #include "base/string16.h" #include "base/timer.h" #include "chrome/common/transport_dib.h" -#include "chrome/browser/child_process_launcher.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/common/notification_registrar.h" #include "third_party/WebKit/WebKit/chromium/public/WebCache.h" @@ -51,8 +49,7 @@ class Size; // are correlated with IDs. This way, the Views and the corresponding ViewHosts // communicate through the two process objects. class BrowserRenderProcessHost : public RenderProcessHost, - public NotificationObserver, - public ChildProcessLauncher::Client { + public NotificationObserver { public: explicit BrowserRenderProcessHost(Profile* profile); ~BrowserRenderProcessHost(); @@ -71,7 +68,6 @@ class BrowserRenderProcessHost : public RenderProcessHost, virtual void WidgetHidden(); virtual void ViewCreated(); virtual void AddWord(const string16& word); - virtual void SendVisitedLinkTable(base::SharedMemory* table_memory); virtual void AddVisitedLinks(const VisitedLinkCommon::Fingerprints& links); virtual void ResetVisitedLinks(); virtual bool FastShutdownIfPossible(); @@ -98,9 +94,6 @@ class BrowserRenderProcessHost : public RenderProcessHost, const NotificationSource& source, const NotificationDetails& details); - // ChildProcessLauncher::Client implementation. - virtual void OnProcessLaunched(); - private: friend class VisitRelayingRenderProcessHost; @@ -129,8 +122,11 @@ class BrowserRenderProcessHost : public RenderProcessHost, void SendUserScriptsUpdate(base::SharedMemory* shared_memory); // Generates a command line to be used to spawn a renderer and appends the - // results to |*command_line|. - void AppendRendererCommandLine(CommandLine* command_line) const; + // results to |*command_line|. |*has_cmd_prefix| will be set if the renderer + // command line specifies a prefix which is another program that will actually + // execute the renderer (like gdb). + void AppendRendererCommandLine(CommandLine* command_line, + bool* has_cmd_prefix) const; // Copies applicable command line switches from the given |browser_cmd| line // flags to the output |renderer_cmd| line flags. Not all switches will be @@ -138,6 +134,13 @@ class BrowserRenderProcessHost : public RenderProcessHost, void PropogateBrowserCommandLineToRenderer(const CommandLine& browser_cmd, CommandLine* renderer_cmd) const; + // Spawns the renderer process, returning the new handle on success, or 0 on + // failure. The renderer command line is given in the first argument, and + // whether a command prefix was used when generating the command line is + // speficied in the second. + base::ProcessHandle ExecuteRenderer(CommandLine* cmd_line, + bool has_cmd_prefix); + // Callers can reduce the RenderProcess' priority. // Returns true if the priority is backgrounded; false otherwise. void SetBackgrounded(bool boost); @@ -198,18 +201,15 @@ class BrowserRenderProcessHost : public RenderProcessHost, // Buffer visited links and send them to to renderer. scoped_ptr<VisitedLinkUpdater> visited_link_updater_; + // True iff the renderer is a child of a zygote process. + bool zygote_child_; + // True iff this process is being used as an extension process. Not valid // when running in single-process mode. bool extension_process_; - // Usedt to launch and terminate the process without blocking the UI thread. - scoped_ptr<ChildProcessLauncher> child_process_; + base::Process process_; - // Messages we queue while waiting for the process handle. We queue them here - // instead of in the channel so that we ensure they're sent after init related - // messages that are sent once the process handle is available. This is - // because the queued messages may have dependencies on the init messages. - std::queue<IPC::Message*> queued_messages_; DISALLOW_COPY_AND_ASSIGN(BrowserRenderProcessHost); }; diff --git a/chrome/browser/renderer_host/mock_render_process_host.cc b/chrome/browser/renderer_host/mock_render_process_host.cc index e2aaa13..7ce8c66 100644 --- a/chrome/browser/renderer_host/mock_render_process_host.cc +++ b/chrome/browser/renderer_host/mock_render_process_host.cc @@ -53,10 +53,6 @@ void MockRenderProcessHost::ViewCreated() { void MockRenderProcessHost::AddWord(const string16& word) { } -void MockRenderProcessHost::SendVisitedLinkTable( - base::SharedMemory* table_memory) { -} - void MockRenderProcessHost::AddVisitedLinks( const VisitedLinkCommon::Fingerprints& links) { } diff --git a/chrome/browser/renderer_host/mock_render_process_host.h b/chrome/browser/renderer_host/mock_render_process_host.h index 4550512..f9e3143 100644 --- a/chrome/browser/renderer_host/mock_render_process_host.h +++ b/chrome/browser/renderer_host/mock_render_process_host.h @@ -43,7 +43,6 @@ class MockRenderProcessHost : public RenderProcessHost { virtual void WidgetHidden(); virtual void ViewCreated(); virtual void AddWord(const string16& word); - virtual void SendVisitedLinkTable(base::SharedMemory* table_memory); virtual void AddVisitedLinks( const VisitedLinkCommon::Fingerprints& visited_links); virtual void ResetVisitedLinks(); diff --git a/chrome/browser/renderer_host/render_process_host.h b/chrome/browser/renderer_host/render_process_host.h index 0914a52..1b2d9ef 100644 --- a/chrome/browser/renderer_host/render_process_host.h +++ b/chrome/browser/renderer_host/render_process_host.h @@ -17,12 +17,9 @@ #include "ipc/ipc_sync_channel.h" class Profile; -class URLRequestContextGetter; struct ViewMsg_ClosePage_Params; -namespace base { -class SharedMemory; -} +class URLRequestContextGetter; // Virtual interface that represents the browser side of the browser <-> // renderer communication channel. There will generally be one @@ -176,9 +173,6 @@ class RenderProcessHost : public IPC::Channel::Sender, // Add a word in the spellchecker. virtual void AddWord(const string16& word) = 0; - // Informs the renderer about a new visited link table. - virtual void SendVisitedLinkTable(base::SharedMemory* table_memory) = 0; - // Notify the renderer that a link was visited. virtual void AddVisitedLinks( const VisitedLinkCommon::Fingerprints& links) = 0; diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 7706c5b..055d68f 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -2139,6 +2139,9 @@ void TabContents::DidStopLoading() { // An entry may not exist for a stop when loading an initial blank page or // if an iframe injected by script into a blank page finishes loading. if (entry) { + scoped_ptr<base::ProcessMetrics> metrics( + base::ProcessMetrics::CreateProcessMetrics(process()->GetHandle())); + base::TimeDelta elapsed = base::TimeTicks::Now() - current_load_start_; details.reset(new LoadNotificationDetails( diff --git a/chrome/browser/visitedlink_event_listener.cc b/chrome/browser/visitedlink_event_listener.cc index 9003fcc..17ca1fd 100644 --- a/chrome/browser/visitedlink_event_listener.cc +++ b/chrome/browser/visitedlink_event_listener.cc @@ -24,7 +24,15 @@ void VisitedLinkEventListener::NewTable(base::SharedMemory* table_memory) { if (!i.GetCurrentValue()->HasConnection()) continue; - i.GetCurrentValue()->SendVisitedLinkTable(table_memory); + base::SharedMemoryHandle new_table; + base::ProcessHandle process = i.GetCurrentValue()->GetHandle(); + if (!process) { + // process can be null if it's started with the --single-process flag. + process = base::Process::Current().handle(); + } + + table_memory->ShareToProcess(process, &new_table); + i.GetCurrentValue()->Send(new ViewMsg_VisitedLink_NewTable(new_table)); } } diff --git a/chrome/browser/visitedlink_master.cc b/chrome/browser/visitedlink_master.cc index 7292551..a7ccd13 100644 --- a/chrome/browser/visitedlink_master.cc +++ b/chrome/browser/visitedlink_master.cc @@ -258,6 +258,19 @@ bool VisitedLinkMaster::Init() { return true; } +bool VisitedLinkMaster::ShareToProcess(base::ProcessHandle process, + base::SharedMemoryHandle *new_handle) { + if (shared_memory_) + return shared_memory_->ShareToProcess(process, new_handle); + + NOTREACHED(); + return false; +} + +base::SharedMemoryHandle VisitedLinkMaster::GetSharedMemoryHandle() { + return shared_memory_->handle(); +} + VisitedLinkMaster::Hash VisitedLinkMaster::TryToAddURL(const GURL& url) { // Extra check that we are not off the record. This should not happen. if (profile_ && profile_->IsOffTheRecord()) { diff --git a/chrome/browser/visitedlink_master.h b/chrome/browser/visitedlink_master.h index fc35ff9..a2bc7b9 100644 --- a/chrome/browser/visitedlink_master.h +++ b/chrome/browser/visitedlink_master.h @@ -80,7 +80,13 @@ class VisitedLinkMaster : public VisitedLinkCommon { // object won't work. bool Init(); - base::SharedMemory* shared_memory() { return shared_memory_; } + // Duplicates the handle to the shared memory to another process. + // Returns true on success. + bool ShareToProcess(base::ProcessHandle process, + base::SharedMemoryHandle *new_handle); + + // Returns the handle to the shared memory + base::SharedMemoryHandle GetSharedMemoryHandle(); // Adds a URL to the table. void AddURL(const GURL& url); diff --git a/chrome/browser/visitedlink_unittest.cc b/chrome/browser/visitedlink_unittest.cc index 3d79355..b873243 100644 --- a/chrome/browser/visitedlink_unittest.cc +++ b/chrome/browser/visitedlink_unittest.cc @@ -131,8 +131,7 @@ class VisitedLinkTest : public testing::Test { // Create a slave database. VisitedLinkSlave slave; base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); - master_->shared_memory()->ShareToProcess( - base::GetCurrentProcessHandle(), &new_handle); + master_->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle); bool success = slave.Init(new_handle); ASSERT_TRUE(success); g_slaves.push_back(&slave); @@ -272,8 +271,7 @@ TEST_F(VisitedLinkTest, DeleteAll) { { VisitedLinkSlave slave; base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); - master_->shared_memory()->ShareToProcess( - base::GetCurrentProcessHandle(), &new_handle); + master_->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle); ASSERT_TRUE(slave.Init(new_handle)); g_slaves.push_back(&slave); @@ -321,8 +319,7 @@ TEST_F(VisitedLinkTest, Resizing) { // ...and a slave VisitedLinkSlave slave; base::SharedMemoryHandle new_handle = base::SharedMemory::NULLHandle(); - master_->shared_memory()->ShareToProcess( - base::GetCurrentProcessHandle(), &new_handle); + master_->ShareToProcess(base::GetCurrentProcessHandle(), &new_handle); bool success = slave.Init(new_handle); ASSERT_TRUE(success); g_slaves.push_back(&slave); |