summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-18 00:03:23 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-18 00:03:23 +0000
commitfdb7ee3dc832589e4ee911a598d4f7fd1054e551 (patch)
tree1f436470c99e3d4f861252de87f686d8048e841b /chrome/browser
parent7d8dc6258b7c9dd771eaf509f5403b602a838388 (diff)
downloadchromium_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.cc238
-rw-r--r--chrome/browser/child_process_launcher.h61
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc14
-rw-r--r--chrome/browser/extensions/extension_host.cc16
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc384
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.h34
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.cc4
-rw-r--r--chrome/browser/renderer_host/mock_render_process_host.h1
-rw-r--r--chrome/browser/renderer_host/render_process_host.h8
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc3
-rw-r--r--chrome/browser/visitedlink_event_listener.cc10
-rw-r--r--chrome/browser/visitedlink_master.cc13
-rw-r--r--chrome/browser/visitedlink_master.h8
-rw-r--r--chrome/browser/visitedlink_unittest.cc9
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);