Browse Source

Copy back the original versions of Chromium files in

Paul Betts 9 years ago
parent
commit
7491d5cfb5

+ 97 - 0
chromium_src/chrome/browser/chrome_process_finder_win.cc

@@ -0,0 +1,97 @@
+// Copyright 2013 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/chrome_process_finder_win.h"
+
+#include <shellapi.h>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/process.h"
+#include "base/process/process_info.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/message_window.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+
+
+namespace {
+
+int timeout_in_milliseconds = 20 * 1000;
+
+}  // namespace
+
+namespace chrome {
+
+HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) {
+  return base::win::MessageWindow::FindWindow(user_data_dir.value());
+}
+
+NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
+                                                bool fast_start) {
+  DCHECK(remote_window);
+  DWORD process_id = 0;
+  DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id);
+  if (!thread_id || !process_id)
+    return NOTIFY_FAILED;
+
+  base::CommandLine command_line(*base::CommandLine::ForCurrentProcess());
+  command_line.AppendSwitchASCII(
+      switches::kOriginalProcessStartTime,
+      base::Int64ToString(
+          base::CurrentProcessInfo::CreationTime().ToInternalValue()));
+
+  if (fast_start)
+    command_line.AppendSwitch(switches::kFastStart);
+
+  // Send the command line to the remote chrome window.
+  // Format is "START\0<<<current directory>>>\0<<<commandline>>>".
+  std::wstring to_send(L"START\0", 6);  // want the NULL in the string.
+  base::FilePath cur_dir;
+  if (!base::GetCurrentDirectory(&cur_dir))
+    return NOTIFY_FAILED;
+  to_send.append(cur_dir.value());
+  to_send.append(L"\0", 1);  // Null separator.
+  to_send.append(command_line.GetCommandLineString());
+  to_send.append(L"\0", 1);  // Null separator.
+
+  // Allow the current running browser window to make itself the foreground
+  // window (otherwise it will just flash in the taskbar).
+  ::AllowSetForegroundWindow(process_id);
+
+  COPYDATASTRUCT cds;
+  cds.dwData = 0;
+  cds.cbData = static_cast<DWORD>((to_send.length() + 1) * sizeof(wchar_t));
+  cds.lpData = const_cast<wchar_t*>(to_send.c_str());
+  DWORD_PTR result = 0;
+  if (::SendMessageTimeout(remote_window, WM_COPYDATA, NULL,
+                           reinterpret_cast<LPARAM>(&cds), SMTO_ABORTIFHUNG,
+                           timeout_in_milliseconds, &result)) {
+    return result ? NOTIFY_SUCCESS : NOTIFY_FAILED;
+  }
+
+  // It is possible that the process owning this window may have died by now.
+  if (!::IsWindow(remote_window))
+    return NOTIFY_FAILED;
+
+  // If the window couldn't be notified but still exists, assume it is hung.
+  return NOTIFY_WINDOW_HUNG;
+}
+
+base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout) {
+  base::TimeDelta old_timeout =
+      base::TimeDelta::FromMilliseconds(timeout_in_milliseconds);
+  timeout_in_milliseconds = new_timeout.InMilliseconds();
+  return old_timeout;
+}
+
+}  // namespace chrome

+ 39 - 0
chromium_src/chrome/browser/chrome_process_finder_win.h

@@ -0,0 +1,39 @@
+// Copyright 2013 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_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
+#define CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_
+
+#include <windows.h>
+
+#include "base/time/time.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace chrome {
+
+enum NotifyChromeResult {
+  NOTIFY_SUCCESS,
+  NOTIFY_FAILED,
+  NOTIFY_WINDOW_HUNG,
+};
+
+// Finds an already running Chrome window if it exists.
+HWND FindRunningChromeWindow(const base::FilePath& user_data_dir);
+
+// Attempts to send the current command line to an already running instance of
+// Chrome via a WM_COPYDATA message.
+// Returns true if a running Chrome is found and successfully notified.
+// |fast_start| is true when this is being called on the window fast start path.
+NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window,
+                                                bool fast_start);
+
+// Changes the notification timeout to |new_timeout|, returns the old timeout.
+base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout);
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_

+ 183 - 0
chromium_src/chrome/browser/process_singleton.h

@@ -0,0 +1,183 @@
+// Copyright (c) 2012 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_BROWSER_PROCESS_SINGLETON_H_
+#define CHROME_BROWSER_PROCESS_SINGLETON_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif  // defined(OS_WIN)
+
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/process/process.h"
+#include "base/threading/non_thread_safe.h"
+#include "ui/gfx/native_widget_types.h"
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#include "base/files/scoped_temp_dir.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/message_window.h"
+#endif  // defined(OS_WIN)
+
+namespace base {
+class CommandLine;
+}
+
+// ProcessSingleton ----------------------------------------------------------
+//
+// This class allows different browser processes to communicate with
+// each other.  It is named according to the user data directory, so
+// we can be sure that no more than one copy of the application can be
+// running at once with a given data directory.
+//
+// Implementation notes:
+// - the Windows implementation uses an invisible global message window;
+// - the Linux implementation uses a Unix domain socket in the user data dir.
+
+class ProcessSingleton : public base::NonThreadSafe {
+ public:
+  enum NotifyResult {
+    PROCESS_NONE,
+    PROCESS_NOTIFIED,
+    PROFILE_IN_USE,
+    LOCK_ERROR,
+  };
+
+  // Implement this callback to handle notifications from other processes. The
+  // callback will receive the command line and directory with which the other
+  // Chrome process was launched. Return true if the command line will be
+  // handled within the current browser instance or false if the remote process
+  // should handle it (i.e., because the current process is shutting down).
+  using NotificationCallback =
+      base::Callback<bool(const base::CommandLine& command_line,
+                          const base::FilePath& current_directory)>;
+
+  ProcessSingleton(const base::FilePath& user_data_dir,
+                   const NotificationCallback& notification_callback);
+  ~ProcessSingleton();
+
+  // Notify another process, if available. Otherwise sets ourselves as the
+  // singleton instance. Returns PROCESS_NONE if we became the singleton
+  // instance. Callers are guaranteed to either have notified an existing
+  // process or have grabbed the singleton (unless the profile is locked by an
+  // unreachable process).
+  // TODO(brettw): Make the implementation of this method non-platform-specific
+  // by making Linux re-use the Windows implementation.
+  NotifyResult NotifyOtherProcessOrCreate();
+
+  // Sets ourself up as the singleton instance.  Returns true on success.  If
+  // false is returned, we are not the singleton instance and the caller must
+  // exit.
+  // NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to
+  // this method, only callers for whom failure is preferred to notifying
+  // another process should call this directly.
+  bool Create();
+
+  // Clear any lock state during shutdown.
+  void Cleanup();
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+  static void DisablePromptForTesting();
+#endif
+#if defined(OS_WIN)
+  // Called to query whether to kill a hung browser process that has visible
+  // windows. Return true to allow killing the hung process.
+  using ShouldKillRemoteProcessCallback = base::Callback<bool()>;
+  void OverrideShouldKillRemoteProcessCallbackForTesting(
+      const ShouldKillRemoteProcessCallback& display_dialog_callback);
+#endif
+
+ protected:
+  // Notify another process, if available.
+  // Returns true if another process was found and notified, false if we should
+  // continue with the current process.
+  // On Windows, Create() has to be called before this.
+  NotifyResult NotifyOtherProcess();
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+  // Exposed for testing.  We use a timeout on Linux, and in tests we want
+  // this timeout to be short.
+  NotifyResult NotifyOtherProcessWithTimeout(
+      const base::CommandLine& command_line,
+      int retry_attempts,
+      const base::TimeDelta& timeout,
+      bool kill_unresponsive);
+  NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
+      const base::CommandLine& command_line,
+      int retry_attempts,
+      const base::TimeDelta& timeout);
+  void OverrideCurrentPidForTesting(base::ProcessId pid);
+  void OverrideKillCallbackForTesting(
+      const base::Callback<void(int)>& callback);
+#endif
+
+ private:
+  NotificationCallback notification_callback_;  // Handler for notifications.
+
+#if defined(OS_WIN)
+  bool EscapeVirtualization(const base::FilePath& user_data_dir);
+
+  HWND remote_window_;  // The HWND_MESSAGE of another browser.
+  base::win::MessageWindow window_;  // The message-only window.
+  bool is_virtualized_;  // Stuck inside Microsoft Softricity VM environment.
+  HANDLE lock_file_;
+  base::FilePath user_data_dir_;
+  ShouldKillRemoteProcessCallback should_kill_remote_process_callback_;
+#elif defined(OS_POSIX) && !defined(OS_ANDROID)
+  // Return true if the given pid is one of our child processes.
+  // Assumes that the current pid is the root of all pids of the current
+  // instance.
+  bool IsSameChromeInstance(pid_t pid);
+
+  // Extract the process's pid from a symbol link path and if it is on
+  // the same host, kill the process, unlink the lock file and return true.
+  // If the process is part of the same chrome instance, unlink the lock file
+  // and return true without killing it.
+  // If the process is on a different host, return false.
+  bool KillProcessByLockPath();
+
+  // Default function to kill a process, overridable by tests.
+  void KillProcess(int pid);
+
+  // Allow overriding for tests.
+  base::ProcessId current_pid_;
+
+  // Function to call when the other process is hung and needs to be killed.
+  // Allows overriding for tests.
+  base::Callback<void(int)> kill_callback_;
+
+  // Path in file system to the socket.
+  base::FilePath socket_path_;
+
+  // Path in file system to the lock.
+  base::FilePath lock_path_;
+
+  // Path in file system to the cookie file.
+  base::FilePath cookie_path_;
+
+  // Temporary directory to hold the socket.
+  base::ScopedTempDir socket_dir_;
+
+  // Helper class for linux specific messages.  LinuxWatcher is ref counted
+  // because it posts messages between threads.
+  class LinuxWatcher;
+  scoped_refptr<LinuxWatcher> watcher_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
+};
+
+#endif  // CHROME_BROWSER_PROCESS_SINGLETON_H_

+ 1062 - 0
chromium_src/chrome/browser/process_singleton_posix.cc

@@ -0,0 +1,1062 @@
+// Copyright 2014 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.
+
+// On Linux, when the user tries to launch a second copy of chrome, we check
+// for a socket in the user's profile directory.  If the socket file is open we
+// send a message to the first chrome browser process with the current
+// directory and second process command line flags.  The second process then
+// exits.
+//
+// Because many networked filesystem implementations do not support unix domain
+// sockets, we create the socket in a temporary directory and create a symlink
+// in the profile. This temporary directory is no longer bound to the profile,
+// and may disappear across a reboot or login to a separate session. To bind
+// them, we store a unique cookie in the profile directory, which must also be
+// present in the remote directory to connect. The cookie is checked both before
+// and after the connection. /tmp is sticky, and different Chrome sessions use
+// different cookies. Thus, a matching cookie before and after means the
+// connection was to a directory with a valid cookie.
+//
+// We also have a lock file, which is a symlink to a non-existent destination.
+// The destination is a string containing the hostname and process id of
+// chrome's browser process, eg. "SingletonLock -> example.com-9156".  When the
+// first copy of chrome exits it will delete the lock file on shutdown, so that
+// a different instance on a different host may then use the profile directory.
+//
+// If writing to the socket fails, the hostname in the lock is checked to see if
+// another instance is running a different host using a shared filesystem (nfs,
+// etc.) If the hostname differs an error is displayed and the second process
+// exits.  Otherwise the first process (if any) is killed and the second process
+// starts as normal.
+//
+// When the second process sends the current directory and command line flags to
+// the first process, it waits for an ACK message back from the first process
+// for a certain time. If there is no ACK message back in time, then the first
+// process will be considered as hung for some reason. The second process then
+// retrieves the process id from the symbol link and kills it by sending
+// SIGKILL. Then the second process starts as normal.
+
+#include "chrome/browser/process_singleton.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <set>
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
+#include "base/rand_util.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_util.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if defined(OS_LINUX)
+#include "chrome/browser/ui/process_singleton_dialog_linux.h"
+#endif
+
+#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "ui/views/linux_ui/linux_ui.h"
+#endif
+
+using content::BrowserThread;
+
+namespace {
+
+// Timeout for the current browser process to respond. 20 seconds should be
+// enough.
+const int kTimeoutInSeconds = 20;
+// Number of retries to notify the browser. 20 retries over 20 seconds = 1 try
+// per second.
+const int kRetryAttempts = 20;
+static bool g_disable_prompt;
+const char kStartToken[] = "START";
+const char kACKToken[] = "ACK";
+const char kShutdownToken[] = "SHUTDOWN";
+const char kTokenDelimiter = '\0';
+const int kMaxMessageLength = 32 * 1024;
+const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
+
+const char kLockDelimiter = '-';
+
+// Set the close-on-exec bit on a file descriptor.
+// Returns 0 on success, -1 on failure.
+int SetCloseOnExec(int fd) {
+  int flags = fcntl(fd, F_GETFD, 0);
+  if (-1 == flags)
+    return flags;
+  if (flags & FD_CLOEXEC)
+    return 0;
+  return fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+}
+
+// Close a socket and check return value.
+void CloseSocket(int fd) {
+  int rv = IGNORE_EINTR(close(fd));
+  DCHECK_EQ(0, rv) << "Error closing socket: " << base::safe_strerror(errno);
+}
+
+// Write a message to a socket fd.
+bool WriteToSocket(int fd, const char *message, size_t length) {
+  DCHECK(message);
+  DCHECK(length);
+  size_t bytes_written = 0;
+  do {
+    ssize_t rv = HANDLE_EINTR(
+        write(fd, message + bytes_written, length - bytes_written));
+    if (rv < 0) {
+      if (errno == EAGAIN || errno == EWOULDBLOCK) {
+        // The socket shouldn't block, we're sending so little data.  Just give
+        // up here, since NotifyOtherProcess() doesn't have an asynchronous api.
+        LOG(ERROR) << "ProcessSingleton would block on write(), so it gave up.";
+        return false;
+      }
+      PLOG(ERROR) << "write() failed";
+      return false;
+    }
+    bytes_written += rv;
+  } while (bytes_written < length);
+
+  return true;
+}
+
+struct timeval TimeDeltaToTimeVal(const base::TimeDelta& delta) {
+  struct timeval result;
+  result.tv_sec = delta.InSeconds();
+  result.tv_usec = delta.InMicroseconds() % base::Time::kMicrosecondsPerSecond;
+  return result;
+}
+
+// Wait a socket for read for a certain timeout.
+// Returns -1 if error occurred, 0 if timeout reached, > 0 if the socket is
+// ready for read.
+int WaitSocketForRead(int fd, const base::TimeDelta& timeout) {
+  fd_set read_fds;
+  struct timeval tv = TimeDeltaToTimeVal(timeout);
+
+  FD_ZERO(&read_fds);
+  FD_SET(fd, &read_fds);
+
+  return HANDLE_EINTR(select(fd + 1, &read_fds, NULL, NULL, &tv));
+}
+
+// Read a message from a socket fd, with an optional timeout.
+// If |timeout| <= 0 then read immediately.
+// Return number of bytes actually read, or -1 on error.
+ssize_t ReadFromSocket(int fd,
+                       char* buf,
+                       size_t bufsize,
+                       const base::TimeDelta& timeout) {
+  if (timeout > base::TimeDelta()) {
+    int rv = WaitSocketForRead(fd, timeout);
+    if (rv <= 0)
+      return rv;
+  }
+
+  size_t bytes_read = 0;
+  do {
+    ssize_t rv = HANDLE_EINTR(read(fd, buf + bytes_read, bufsize - bytes_read));
+    if (rv < 0) {
+      if (errno != EAGAIN && errno != EWOULDBLOCK) {
+        PLOG(ERROR) << "read() failed";
+        return rv;
+      } else {
+        // It would block, so we just return what has been read.
+        return bytes_read;
+      }
+    } else if (!rv) {
+      // No more data to read.
+      return bytes_read;
+    } else {
+      bytes_read += rv;
+    }
+  } while (bytes_read < bufsize);
+
+  return bytes_read;
+}
+
+// Set up a sockaddr appropriate for messaging.
+void SetupSockAddr(const std::string& path, struct sockaddr_un* addr) {
+  addr->sun_family = AF_UNIX;
+  CHECK(path.length() < arraysize(addr->sun_path))
+      << "Socket path too long: " << path;
+  base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path));
+}
+
+// Set up a socket appropriate for messaging.
+int SetupSocketOnly() {
+  int sock = socket(PF_UNIX, SOCK_STREAM, 0);
+  PCHECK(sock >= 0) << "socket() failed";
+
+  int rv = net::SetNonBlocking(sock);
+  DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
+  rv = SetCloseOnExec(sock);
+  DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";
+
+  return sock;
+}
+
+// Set up a socket and sockaddr appropriate for messaging.
+void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
+  *sock = SetupSocketOnly();
+  SetupSockAddr(path, addr);
+}
+
+// Read a symbolic link, return empty string if given path is not a symbol link.
+base::FilePath ReadLink(const base::FilePath& path) {
+  base::FilePath target;
+  if (!base::ReadSymbolicLink(path, &target)) {
+    // The only errno that should occur is ENOENT.
+    if (errno != 0 && errno != ENOENT)
+      PLOG(ERROR) << "readlink(" << path.value() << ") failed";
+  }
+  return target;
+}
+
+// Unlink a path. Return true on success.
+bool UnlinkPath(const base::FilePath& path) {
+  int rv = unlink(path.value().c_str());
+  if (rv < 0 && errno != ENOENT)
+    PLOG(ERROR) << "Failed to unlink " << path.value();
+
+  return rv == 0;
+}
+
+// Create a symlink. Returns true on success.
+bool SymlinkPath(const base::FilePath& target, const base::FilePath& path) {
+  if (!base::CreateSymbolicLink(target, path)) {
+    // Double check the value in case symlink suceeded but we got an incorrect
+    // failure due to NFS packet loss & retry.
+    int saved_errno = errno;
+    if (ReadLink(path) != target) {
+      // If we failed to create the lock, most likely another instance won the
+      // startup race.
+      errno = saved_errno;
+      PLOG(ERROR) << "Failed to create " << path.value();
+      return false;
+    }
+  }
+  return true;
+}
+
+// Extract the hostname and pid from the lock symlink.
+// Returns true if the lock existed.
+bool ParseLockPath(const base::FilePath& path,
+                   std::string* hostname,
+                   int* pid) {
+  std::string real_path = ReadLink(path).value();
+  if (real_path.empty())
+    return false;
+
+  std::string::size_type pos = real_path.rfind(kLockDelimiter);
+
+  // If the path is not a symbolic link, or doesn't contain what we expect,
+  // bail.
+  if (pos == std::string::npos) {
+    *hostname = "";
+    *pid = -1;
+    return true;
+  }
+
+  *hostname = real_path.substr(0, pos);
+
+  const std::string& pid_str = real_path.substr(pos + 1);
+  if (!base::StringToInt(pid_str, pid))
+    *pid = -1;
+
+  return true;
+}
+
+// Returns true if the user opted to unlock the profile.
+bool DisplayProfileInUseError(const base::FilePath& lock_path,
+                              const std::string& hostname,
+                              int pid) {
+  base::string16 error = l10n_util::GetStringFUTF16(
+      IDS_PROFILE_IN_USE_POSIX,
+      base::IntToString16(pid),
+      base::ASCIIToUTF16(hostname));
+  LOG(ERROR) << error;
+
+  if (g_disable_prompt)
+    return false;
+
+#if defined(OS_LINUX)
+  base::string16 relaunch_button_text = l10n_util::GetStringUTF16(
+      IDS_PROFILE_IN_USE_LINUX_RELAUNCH);
+  return ShowProcessSingletonDialog(error, relaunch_button_text);
+#elif defined(OS_MACOSX)
+  // On Mac, always usurp the lock.
+  return true;
+#endif
+
+  NOTREACHED();
+  return false;
+}
+
+bool IsChromeProcess(pid_t pid) {
+  base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid));
+  return (!other_chrome_path.empty() &&
+          other_chrome_path.BaseName() ==
+          base::FilePath(chrome::kBrowserProcessExecutableName));
+}
+
+// A helper class to hold onto a socket.
+class ScopedSocket {
+ public:
+  ScopedSocket() : fd_(-1) { Reset(); }
+  ~ScopedSocket() { Close(); }
+  int fd() { return fd_; }
+  void Reset() {
+    Close();
+    fd_ = SetupSocketOnly();
+  }
+  void Close() {
+    if (fd_ >= 0)
+      CloseSocket(fd_);
+    fd_ = -1;
+  }
+ private:
+  int fd_;
+};
+
+// Returns a random string for uniquifying profile connections.
+std::string GenerateCookie() {
+  return base::Uint64ToString(base::RandUint64());
+}
+
+bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) {
+  return (cookie == ReadLink(path));
+}
+
+bool ConnectSocket(ScopedSocket* socket,
+                   const base::FilePath& socket_path,
+                   const base::FilePath& cookie_path) {
+  base::FilePath socket_target;
+  if (base::ReadSymbolicLink(socket_path, &socket_target)) {
+    // It's a symlink. Read the cookie.
+    base::FilePath cookie = ReadLink(cookie_path);
+    if (cookie.empty())
+      return false;
+    base::FilePath remote_cookie = socket_target.DirName().
+                             Append(chrome::kSingletonCookieFilename);
+    // Verify the cookie before connecting.
+    if (!CheckCookie(remote_cookie, cookie))
+      return false;
+    // Now we know the directory was (at that point) created by the profile
+    // owner. Try to connect.
+    sockaddr_un addr;
+    SetupSockAddr(socket_target.value(), &addr);
+    int ret = HANDLE_EINTR(connect(socket->fd(),
+                                   reinterpret_cast<sockaddr*>(&addr),
+                                   sizeof(addr)));
+    if (ret != 0)
+      return false;
+    // Check the cookie again. We only link in /tmp, which is sticky, so, if the
+    // directory is still correct, it must have been correct in-between when we
+    // connected. POSIX, sadly, lacks a connectat().
+    if (!CheckCookie(remote_cookie, cookie)) {
+      socket->Reset();
+      return false;
+    }
+    // Success!
+    return true;
+  } else if (errno == EINVAL) {
+    // It exists, but is not a symlink (or some other error we detect
+    // later). Just connect to it directly; this is an older version of Chrome.
+    sockaddr_un addr;
+    SetupSockAddr(socket_path.value(), &addr);
+    int ret = HANDLE_EINTR(connect(socket->fd(),
+                                   reinterpret_cast<sockaddr*>(&addr),
+                                   sizeof(addr)));
+    return (ret == 0);
+  } else {
+    // File is missing, or other error.
+    if (errno != ENOENT)
+      PLOG(ERROR) << "readlink failed";
+    return false;
+  }
+}
+
+#if defined(OS_MACOSX)
+bool ReplaceOldSingletonLock(const base::FilePath& symlink_content,
+                             const base::FilePath& lock_path) {
+  // Try taking an flock(2) on the file. Failure means the lock is taken so we
+  // should quit.
+  base::ScopedFD lock_fd(HANDLE_EINTR(
+      open(lock_path.value().c_str(), O_RDWR | O_CREAT | O_SYMLINK, 0644)));
+  if (!lock_fd.is_valid()) {
+    PLOG(ERROR) << "Could not open singleton lock";
+    return false;
+  }
+
+  int rc = HANDLE_EINTR(flock(lock_fd.get(), LOCK_EX | LOCK_NB));
+  if (rc == -1) {
+    if (errno == EWOULDBLOCK) {
+      LOG(ERROR) << "Singleton lock held by old process.";
+    } else {
+      PLOG(ERROR) << "Error locking singleton lock";
+    }
+    return false;
+  }
+
+  // Successfully taking the lock means we can replace it with the a new symlink
+  // lock. We never flock() the lock file from now on. I.e. we assume that an
+  // old version of Chrome will not run with the same user data dir after this
+  // version has run.
+  if (!base::DeleteFile(lock_path, false)) {
+    PLOG(ERROR) << "Could not delete old singleton lock.";
+    return false;
+  }
+
+  return SymlinkPath(symlink_content, lock_path);
+}
+#endif  // defined(OS_MACOSX)
+
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// ProcessSingleton::LinuxWatcher
+// A helper class for a Linux specific implementation of the process singleton.
+// This class sets up a listener on the singleton socket and handles parsing
+// messages that come in on the singleton socket.
+class ProcessSingleton::LinuxWatcher
+    : public base::MessageLoopForIO::Watcher,
+      public base::MessageLoop::DestructionObserver,
+      public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher,
+                                        BrowserThread::DeleteOnIOThread> {
+ public:
+  // A helper class to read message from an established socket.
+  class SocketReader : public base::MessageLoopForIO::Watcher {
+   public:
+    SocketReader(ProcessSingleton::LinuxWatcher* parent,
+                 base::MessageLoop* ui_message_loop,
+                 int fd)
+        : parent_(parent),
+          ui_message_loop_(ui_message_loop),
+          fd_(fd),
+          bytes_read_(0) {
+      DCHECK_CURRENTLY_ON(BrowserThread::IO);
+      // Wait for reads.
+      base::MessageLoopForIO::current()->WatchFileDescriptor(
+          fd, true, base::MessageLoopForIO::WATCH_READ, &fd_reader_, this);
+      // If we haven't completed in a reasonable amount of time, give up.
+      timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kTimeoutInSeconds),
+                   this, &SocketReader::CleanupAndDeleteSelf);
+    }
+
+    ~SocketReader() override { CloseSocket(fd_); }
+
+    // MessageLoopForIO::Watcher impl.
+    void OnFileCanReadWithoutBlocking(int fd) override;
+    void OnFileCanWriteWithoutBlocking(int fd) override {
+      // SocketReader only watches for accept (read) events.
+      NOTREACHED();
+    }
+
+    // Finish handling the incoming message by optionally sending back an ACK
+    // message and removing this SocketReader.
+    void FinishWithACK(const char *message, size_t length);
+
+   private:
+    void CleanupAndDeleteSelf() {
+      DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+      parent_->RemoveSocketReader(this);
+      // We're deleted beyond this point.
+    }
+
+    base::MessageLoopForIO::FileDescriptorWatcher fd_reader_;
+
+    // The ProcessSingleton::LinuxWatcher that owns us.
+    ProcessSingleton::LinuxWatcher* const parent_;
+
+    // A reference to the UI message loop.
+    base::MessageLoop* const ui_message_loop_;
+
+    // The file descriptor we're reading.
+    const int fd_;
+
+    // Store the message in this buffer.
+    char buf_[kMaxMessageLength];
+
+    // Tracks the number of bytes we've read in case we're getting partial
+    // reads.
+    size_t bytes_read_;
+
+    base::OneShotTimer timer_;
+
+    DISALLOW_COPY_AND_ASSIGN(SocketReader);
+  };
+
+  // We expect to only be constructed on the UI thread.
+  explicit LinuxWatcher(ProcessSingleton* parent)
+      : ui_message_loop_(base::MessageLoop::current()),
+        parent_(parent) {
+  }
+
+  // Start listening for connections on the socket.  This method should be
+  // called from the IO thread.
+  void StartListening(int socket);
+
+  // This method determines if we should use the same process and if we should,
+  // opens a new browser tab.  This runs on the UI thread.
+  // |reader| is for sending back ACK message.
+  void HandleMessage(const std::string& current_dir,
+                     const std::vector<std::string>& argv,
+                     SocketReader* reader);
+
+  // MessageLoopForIO::Watcher impl.  These run on the IO thread.
+  void OnFileCanReadWithoutBlocking(int fd) override;
+  void OnFileCanWriteWithoutBlocking(int fd) override {
+    // ProcessSingleton only watches for accept (read) events.
+    NOTREACHED();
+  }
+
+  // MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override {
+    fd_watcher_.StopWatchingFileDescriptor();
+  }
+
+ private:
+  friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
+  friend class base::DeleteHelper<ProcessSingleton::LinuxWatcher>;
+
+  ~LinuxWatcher() override {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    STLDeleteElements(&readers_);
+
+    base::MessageLoopForIO* ml = base::MessageLoopForIO::current();
+    ml->RemoveDestructionObserver(this);
+  }
+
+  // Removes and deletes the SocketReader.
+  void RemoveSocketReader(SocketReader* reader);
+
+  base::MessageLoopForIO::FileDescriptorWatcher fd_watcher_;
+
+  // A reference to the UI message loop (i.e., the message loop we were
+  // constructed on).
+  base::MessageLoop* ui_message_loop_;
+
+  // The ProcessSingleton that owns us.
+  ProcessSingleton* const parent_;
+
+  std::set<SocketReader*> readers_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinuxWatcher);
+};
+
+void ProcessSingleton::LinuxWatcher::OnFileCanReadWithoutBlocking(int fd) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  // Accepting incoming client.
+  sockaddr_un from;
+  socklen_t from_len = sizeof(from);
+  int connection_socket = HANDLE_EINTR(accept(
+      fd, reinterpret_cast<sockaddr*>(&from), &from_len));
+  if (-1 == connection_socket) {
+    PLOG(ERROR) << "accept() failed";
+    return;
+  }
+  int rv = net::SetNonBlocking(connection_socket);
+  DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
+  SocketReader* reader = new SocketReader(this,
+                                          ui_message_loop_,
+                                          connection_socket);
+  readers_.insert(reader);
+}
+
+void ProcessSingleton::LinuxWatcher::StartListening(int socket) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  // Watch for client connections on this socket.
+  base::MessageLoopForIO* ml = base::MessageLoopForIO::current();
+  ml->AddDestructionObserver(this);
+  ml->WatchFileDescriptor(socket, true, base::MessageLoopForIO::WATCH_READ,
+                          &fd_watcher_, this);
+}
+
+void ProcessSingleton::LinuxWatcher::HandleMessage(
+    const std::string& current_dir, const std::vector<std::string>& argv,
+    SocketReader* reader) {
+  DCHECK(ui_message_loop_ == base::MessageLoop::current());
+  DCHECK(reader);
+
+  if (parent_->notification_callback_.Run(base::CommandLine(argv),
+                                          base::FilePath(current_dir))) {
+    // Send back "ACK" message to prevent the client process from starting up.
+    reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1);
+  } else {
+    LOG(WARNING) << "Not handling interprocess notification as browser"
+                    " is shutting down";
+    // Send back "SHUTDOWN" message, so that the client process can start up
+    // without killing this process.
+    reader->FinishWithACK(kShutdownToken, arraysize(kShutdownToken) - 1);
+    return;
+  }
+}
+
+void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(reader);
+  readers_.erase(reader);
+  delete reader;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ProcessSingleton::LinuxWatcher::SocketReader
+//
+
+void ProcessSingleton::LinuxWatcher::SocketReader::OnFileCanReadWithoutBlocking(
+    int fd) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_EQ(fd, fd_);
+  while (bytes_read_ < sizeof(buf_)) {
+    ssize_t rv = HANDLE_EINTR(
+        read(fd, buf_ + bytes_read_, sizeof(buf_) - bytes_read_));
+    if (rv < 0) {
+      if (errno != EAGAIN && errno != EWOULDBLOCK) {
+        PLOG(ERROR) << "read() failed";
+        CloseSocket(fd);
+        return;
+      } else {
+        // It would block, so we just return and continue to watch for the next
+        // opportunity to read.
+        return;
+      }
+    } else if (!rv) {
+      // No more data to read.  It's time to process the message.
+      break;
+    } else {
+      bytes_read_ += rv;
+    }
+  }
+
+  // Validate the message.  The shortest message is kStartToken\0x\0x
+  const size_t kMinMessageLength = arraysize(kStartToken) + 4;
+  if (bytes_read_ < kMinMessageLength) {
+    buf_[bytes_read_] = 0;
+    LOG(ERROR) << "Invalid socket message (wrong length):" << buf_;
+    CleanupAndDeleteSelf();
+    return;
+  }
+
+  std::string str(buf_, bytes_read_);
+  std::vector<std::string> tokens = base::SplitString(
+      str, std::string(1, kTokenDelimiter),
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+
+  if (tokens.size() < 3 || tokens[0] != kStartToken) {
+    LOG(ERROR) << "Wrong message format: " << str;
+    CleanupAndDeleteSelf();
+    return;
+  }
+
+  // Stop the expiration timer to prevent this SocketReader object from being
+  // terminated unexpectly.
+  timer_.Stop();
+
+  std::string current_dir = tokens[1];
+  // Remove the first two tokens.  The remaining tokens should be the command
+  // line argv array.
+  tokens.erase(tokens.begin());
+  tokens.erase(tokens.begin());
+
+  // Return to the UI thread to handle opening a new browser tab.
+  ui_message_loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&ProcessSingleton::LinuxWatcher::HandleMessage,
+                            parent_, current_dir, tokens, this));
+  fd_reader_.StopWatchingFileDescriptor();
+
+  // LinuxWatcher::HandleMessage() is in charge of destroying this SocketReader
+  // object by invoking SocketReader::FinishWithACK().
+}
+
+void ProcessSingleton::LinuxWatcher::SocketReader::FinishWithACK(
+    const char *message, size_t length) {
+  if (message && length) {
+    // Not necessary to care about the return value.
+    WriteToSocket(fd_, message, length);
+  }
+
+  if (shutdown(fd_, SHUT_WR) < 0)
+    PLOG(ERROR) << "shutdown() failed";
+
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&ProcessSingleton::LinuxWatcher::RemoveSocketReader,
+                 parent_,
+                 this));
+  // We will be deleted once the posted RemoveSocketReader task runs.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ProcessSingleton
+//
+ProcessSingleton::ProcessSingleton(
+    const base::FilePath& user_data_dir,
+    const NotificationCallback& notification_callback)
+    : notification_callback_(notification_callback),
+      current_pid_(base::GetCurrentProcId()),
+      watcher_(new LinuxWatcher(this)) {
+  socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
+  lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
+  cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename);
+
+  kill_callback_ = base::Bind(&ProcessSingleton::KillProcess,
+                              base::Unretained(this));
+}
+
+ProcessSingleton::~ProcessSingleton() {
+}
+
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
+  return NotifyOtherProcessWithTimeout(
+      *base::CommandLine::ForCurrentProcess(), kRetryAttempts,
+      base::TimeDelta::FromSeconds(kTimeoutInSeconds), true);
+}
+
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
+    const base::CommandLine& cmd_line,
+    int retry_attempts,
+    const base::TimeDelta& timeout,
+    bool kill_unresponsive) {
+  DCHECK_GE(retry_attempts, 0);
+  DCHECK_GE(timeout.InMicroseconds(), 0);
+
+  base::TimeDelta sleep_interval = timeout / retry_attempts;
+
+  ScopedSocket socket;
+  for (int retries = 0; retries <= retry_attempts; ++retries) {
+    // Try to connect to the socket.
+    if (ConnectSocket(&socket, socket_path_, cookie_path_))
+      break;
+
+    // If we're in a race with another process, they may be in Create() and have
+    // created the lock but not attached to the socket.  So we check if the
+    // process with the pid from the lockfile is currently running and is a
+    // chrome browser.  If so, we loop and try again for |timeout|.
+
+    std::string hostname;
+    int pid;
+    if (!ParseLockPath(lock_path_, &hostname, &pid)) {
+      // No lockfile exists.
+      return PROCESS_NONE;
+    }
+
+    if (hostname.empty()) {
+      // Invalid lockfile.
+      UnlinkPath(lock_path_);
+      return PROCESS_NONE;
+    }
+
+    if (hostname != net::GetHostName() && !IsChromeProcess(pid)) {
+      // Locked by process on another host. If the user selected to unlock
+      // the profile, try to continue; otherwise quit.
+      if (DisplayProfileInUseError(lock_path_, hostname, pid)) {
+        UnlinkPath(lock_path_);
+        return PROCESS_NONE;
+      }
+      return PROFILE_IN_USE;
+    }
+
+    if (!IsChromeProcess(pid)) {
+      // Orphaned lockfile (no process with pid, or non-chrome process.)
+      UnlinkPath(lock_path_);
+      return PROCESS_NONE;
+    }
+
+    if (IsSameChromeInstance(pid)) {
+      // Orphaned lockfile (pid is part of same chrome instance we are, even
+      // though we haven't tried to create a lockfile yet).
+      UnlinkPath(lock_path_);
+      return PROCESS_NONE;
+    }
+
+    if (retries == retry_attempts) {
+      // Retries failed.  Kill the unresponsive chrome process and continue.
+      if (!kill_unresponsive || !KillProcessByLockPath())
+        return PROFILE_IN_USE;
+      return PROCESS_NONE;
+    }
+
+    base::PlatformThread::Sleep(sleep_interval);
+  }
+
+  timeval socket_timeout = TimeDeltaToTimeVal(timeout);
+  setsockopt(socket.fd(),
+             SOL_SOCKET,
+             SO_SNDTIMEO,
+             &socket_timeout,
+             sizeof(socket_timeout));
+
+  // Found another process, prepare our command line
+  // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
+  std::string to_send(kStartToken);
+  to_send.push_back(kTokenDelimiter);
+
+  base::FilePath current_dir;
+  if (!PathService::Get(base::DIR_CURRENT, &current_dir))
+    return PROCESS_NONE;
+  to_send.append(current_dir.value());
+
+  const std::vector<std::string>& argv = cmd_line.argv();
+  for (std::vector<std::string>::const_iterator it = argv.begin();
+      it != argv.end(); ++it) {
+    to_send.push_back(kTokenDelimiter);
+    to_send.append(*it);
+  }
+
+  // Send the message
+  if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) {
+    // Try to kill the other process, because it might have been dead.
+    if (!kill_unresponsive || !KillProcessByLockPath())
+      return PROFILE_IN_USE;
+    return PROCESS_NONE;
+  }
+
+  if (shutdown(socket.fd(), SHUT_WR) < 0)
+    PLOG(ERROR) << "shutdown() failed";
+
+  // Read ACK message from the other process. It might be blocked for a certain
+  // timeout, to make sure the other process has enough time to return ACK.
+  char buf[kMaxACKMessageLength + 1];
+  ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout);
+
+  // Failed to read ACK, the other process might have been frozen.
+  if (len <= 0) {
+    if (!kill_unresponsive || !KillProcessByLockPath())
+      return PROFILE_IN_USE;
+    return PROCESS_NONE;
+  }
+
+  buf[len] = '\0';
+  if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
+    // The other process is shutting down, it's safe to start a new process.
+    return PROCESS_NONE;
+  } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) {
+#if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
+    // Likely NULL in unit tests.
+    views::LinuxUI* linux_ui = views::LinuxUI::instance();
+    if (linux_ui)
+      linux_ui->NotifyWindowManagerStartupComplete();
+#endif
+
+    // Assume the other process is handling the request.
+    return PROCESS_NOTIFIED;
+  }
+
+  NOTREACHED() << "The other process returned unknown message: " << buf;
+  return PROCESS_NOTIFIED;
+}
+
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
+  return NotifyOtherProcessWithTimeoutOrCreate(
+      *base::CommandLine::ForCurrentProcess(), kRetryAttempts,
+      base::TimeDelta::FromSeconds(kTimeoutInSeconds));
+}
+
+ProcessSingleton::NotifyResult
+ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
+    const base::CommandLine& command_line,
+    int retry_attempts,
+    const base::TimeDelta& timeout) {
+  NotifyResult result = NotifyOtherProcessWithTimeout(
+      command_line, retry_attempts, timeout, true);
+  if (result != PROCESS_NONE)
+    return result;
+  if (Create())
+    return PROCESS_NONE;
+  // If the Create() failed, try again to notify. (It could be that another
+  // instance was starting at the same time and managed to grab the lock before
+  // we did.)
+  // This time, we don't want to kill anything if we aren't successful, since we
+  // aren't going to try to take over the lock ourselves.
+  result = NotifyOtherProcessWithTimeout(
+      command_line, retry_attempts, timeout, false);
+  if (result != PROCESS_NONE)
+    return result;
+
+  return LOCK_ERROR;
+}
+
+void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) {
+  current_pid_ = pid;
+}
+
+void ProcessSingleton::OverrideKillCallbackForTesting(
+    const base::Callback<void(int)>& callback) {
+  kill_callback_ = callback;
+}
+
+void ProcessSingleton::DisablePromptForTesting() {
+  g_disable_prompt = true;
+}
+
+bool ProcessSingleton::Create() {
+  int sock;
+  sockaddr_un addr;
+
+  // The symlink lock is pointed to the hostname and process id, so other
+  // processes can find it out.
+  base::FilePath symlink_content(base::StringPrintf(
+      "%s%c%u",
+      net::GetHostName().c_str(),
+      kLockDelimiter,
+      current_pid_));
+
+  // Create symbol link before binding the socket, to ensure only one instance
+  // can have the socket open.
+  if (!SymlinkPath(symlink_content, lock_path_)) {
+    // TODO(jackhou): Remove this case once this code is stable on Mac.
+    // http://crbug.com/367612
+#if defined(OS_MACOSX)
+    // On Mac, an existing non-symlink lock file means the lock could be held by
+    // the old process singleton code. If we can successfully replace the lock,
+    // continue as normal.
+    if (base::IsLink(lock_path_) ||
+        !ReplaceOldSingletonLock(symlink_content, lock_path_)) {
+      return false;
+    }
+#else
+    // If we failed to create the lock, most likely another instance won the
+    // startup race.
+    return false;
+#endif
+  }
+
+  // Create the socket file somewhere in /tmp which is usually mounted as a
+  // normal filesystem. Some network filesystems (notably AFS) are screwy and
+  // do not support Unix domain sockets.
+  if (!socket_dir_.CreateUniqueTempDir()) {
+    LOG(ERROR) << "Failed to create socket directory.";
+    return false;
+  }
+
+  // Check that the directory was created with the correct permissions.
+  int dir_mode = 0;
+  CHECK(base::GetPosixFilePermissions(socket_dir_.path(), &dir_mode) &&
+        dir_mode == base::FILE_PERMISSION_USER_MASK)
+      << "Temp directory mode is not 700: " << std::oct << dir_mode;
+
+  // Setup the socket symlink and the two cookies.
+  base::FilePath socket_target_path =
+      socket_dir_.path().Append(chrome::kSingletonSocketFilename);
+  base::FilePath cookie(GenerateCookie());
+  base::FilePath remote_cookie_path =
+      socket_dir_.path().Append(chrome::kSingletonCookieFilename);
+  UnlinkPath(socket_path_);
+  UnlinkPath(cookie_path_);
+  if (!SymlinkPath(socket_target_path, socket_path_) ||
+      !SymlinkPath(cookie, cookie_path_) ||
+      !SymlinkPath(cookie, remote_cookie_path)) {
+    // We've already locked things, so we can't have lost the startup race,
+    // but something doesn't like us.
+    LOG(ERROR) << "Failed to create symlinks.";
+    if (!socket_dir_.Delete())
+      LOG(ERROR) << "Encountered a problem when deleting socket directory.";
+    return false;
+  }
+
+  SetupSocket(socket_target_path.value(), &sock, &addr);
+
+  if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
+    PLOG(ERROR) << "Failed to bind() " << socket_target_path.value();
+    CloseSocket(sock);
+    return false;
+  }
+
+  if (listen(sock, 5) < 0)
+    NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
+
+  DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
+  BrowserThread::PostTask(
+      BrowserThread::IO,
+      FROM_HERE,
+      base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
+                 watcher_.get(),
+                 sock));
+
+  return true;
+}
+
+void ProcessSingleton::Cleanup() {
+  UnlinkPath(socket_path_);
+  UnlinkPath(cookie_path_);
+  UnlinkPath(lock_path_);
+}
+
+bool ProcessSingleton::IsSameChromeInstance(pid_t pid) {
+  pid_t cur_pid = current_pid_;
+  while (pid != cur_pid) {
+    pid = base::GetParentProcessId(pid);
+    if (pid < 0)
+      return false;
+    if (!IsChromeProcess(pid))
+      return false;
+  }
+  return true;
+}
+
+bool ProcessSingleton::KillProcessByLockPath() {
+  std::string hostname;
+  int pid;
+  ParseLockPath(lock_path_, &hostname, &pid);
+
+  if (!hostname.empty() && hostname != net::GetHostName()) {
+    return DisplayProfileInUseError(lock_path_, hostname, pid);
+  }
+  UnlinkPath(lock_path_);
+
+  if (IsSameChromeInstance(pid))
+    return true;
+
+  if (pid > 0) {
+    kill_callback_.Run(pid);
+    return true;
+  }
+
+  LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value();
+  return true;
+}
+
+void ProcessSingleton::KillProcess(int pid) {
+  // TODO([email protected]): Is SIGKILL ok?
+  int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
+  // ESRCH = No Such Process (can happen if the other process is already in
+  // progress of shutting down and finishes before we try to kill it).
+  DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
+                                    << base::safe_strerror(errno);
+}

+ 53 - 0
chromium_src/chrome/browser/process_singleton_startup_lock.cc

@@ -0,0 +1,53 @@
+// Copyright (c) 2013 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/process_singleton_startup_lock.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+ProcessSingletonStartupLock::ProcessSingletonStartupLock(
+    const ProcessSingleton::NotificationCallback& original_callback)
+    : locked_(true),
+      original_callback_(original_callback) {}
+
+ProcessSingletonStartupLock::~ProcessSingletonStartupLock() {}
+
+ProcessSingleton::NotificationCallback
+ProcessSingletonStartupLock::AsNotificationCallback() {
+  return base::Bind(&ProcessSingletonStartupLock::NotificationCallbackImpl,
+                    base::Unretained(this));
+}
+
+void ProcessSingletonStartupLock::Unlock() {
+  DCHECK(CalledOnValidThread());
+  locked_ = false;
+
+  // Replay the command lines of the messages which were received while the
+  // ProcessSingleton was locked. Only replay each message once.
+  std::set<DelayedStartupMessage> replayed_messages;
+  for (std::vector<DelayedStartupMessage>::const_iterator it =
+           saved_startup_messages_.begin();
+       it != saved_startup_messages_.end(); ++it) {
+    if (replayed_messages.find(*it) != replayed_messages.end())
+      continue;
+    original_callback_.Run(base::CommandLine(it->first), it->second);
+    replayed_messages.insert(*it);
+  }
+  saved_startup_messages_.clear();
+}
+
+bool ProcessSingletonStartupLock::NotificationCallbackImpl(
+    const base::CommandLine& command_line,
+    const base::FilePath& current_directory) {
+  if (locked_) {
+    // If locked, it means we are not ready to process this message because
+    // we are probably in a first run critical phase.
+    saved_startup_messages_.push_back(
+        std::make_pair(command_line.argv(), current_directory));
+    return true;
+  } else {
+    return original_callback_.Run(command_line, current_directory);
+  }
+}

+ 57 - 0
chromium_src/chrome/browser/process_singleton_startup_lock.h

@@ -0,0 +1,57 @@
+// Copyright (c) 2013 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_BROWSER_PROCESS_SINGLETON_STARTUP_LOCK_H_
+#define CHROME_BROWSER_PROCESS_SINGLETON_STARTUP_LOCK_H_
+
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/threading/non_thread_safe.h"
+#include "chrome/browser/process_singleton.h"
+
+// Provides a ProcessSingleton::NotificationCallback that can queue up
+// command-line invocations during startup and execute them when startup
+// completes.
+//
+// The object starts in a locked state. |Unlock()| must be called
+// when the process is prepared to handle command-line invocations.
+//
+// Once unlocked, notifications are forwarded to a wrapped NotificationCallback.
+class ProcessSingletonStartupLock : public base::NonThreadSafe {
+ public:
+  explicit ProcessSingletonStartupLock(
+      const ProcessSingleton::NotificationCallback& original_callback);
+  ~ProcessSingletonStartupLock();
+
+  // Returns the ProcessSingleton::NotificationCallback.
+  // The callback is only valid during the lifetime of the
+  // ProcessSingletonStartupLock instance.
+  ProcessSingleton::NotificationCallback AsNotificationCallback();
+
+  // Executes previously queued command-line invocations and allows future
+  // invocations to be executed immediately.
+  void Unlock();
+
+  bool locked() { return locked_; }
+
+ private:
+  typedef std::pair<base::CommandLine::StringVector, base::FilePath>
+      DelayedStartupMessage;
+
+  bool NotificationCallbackImpl(const base::CommandLine& command_line,
+                                const base::FilePath& current_directory);
+
+  bool locked_;
+  std::vector<DelayedStartupMessage> saved_startup_messages_;
+  ProcessSingleton::NotificationCallback original_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessSingletonStartupLock);
+};
+
+#endif  // CHROME_BROWSER_PROCESS_SINGLETON_STARTUP_LOCK_H_

+ 441 - 0
chromium_src/chrome/browser/process_singleton_win.cc

@@ -0,0 +1,441 @@
+// Copyright (c) 2012 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/process_singleton.h"
+
+#include <shellapi.h>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "base/process/process_info.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/win/metro.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
+#include "chrome/browser/chrome_process_finder_win.h"
+#include "chrome/browser/metro_utils/metro_chrome_win.h"
+#include "chrome/browser/shell_integration.h"
+#include "chrome/browser/ui/simple_message_box.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_paths_internal.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/installer/util/wmi.h"
+#include "content/public/common/result_codes.h"
+#include "net/base/escape.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/win/hwnd_util.h"
+
+namespace {
+
+const char kLockfile[] = "lockfile";
+
+const int kMetroChromeActivationTimeoutMs = 3000;
+
+// A helper class that acquires the given |mutex| while the AutoLockMutex is in
+// scope.
+class AutoLockMutex {
+ public:
+  explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) {
+    DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
+    DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
+  }
+
+  ~AutoLockMutex() {
+    BOOL released = ::ReleaseMutex(mutex_);
+    DPCHECK(released);
+  }
+
+ private:
+  HANDLE mutex_;
+  DISALLOW_COPY_AND_ASSIGN(AutoLockMutex);
+};
+
+// A helper class that releases the given |mutex| while the AutoUnlockMutex is
+// in scope and immediately re-acquires it when going out of scope.
+class AutoUnlockMutex {
+ public:
+  explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) {
+    BOOL released = ::ReleaseMutex(mutex_);
+    DPCHECK(released);
+  }
+
+  ~AutoUnlockMutex() {
+    DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
+    DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
+  }
+
+ private:
+  HANDLE mutex_;
+  DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex);
+};
+
+// Checks the visibility of the enumerated window and signals once a visible
+// window has been found.
+BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
+  bool* result = reinterpret_cast<bool*>(param);
+  *result = ::IsWindowVisible(window) != 0;
+  // Stops enumeration if a visible window has been found.
+  return !*result;
+}
+
+bool ParseCommandLine(const COPYDATASTRUCT* cds,
+                      base::CommandLine* parsed_command_line,
+                      base::FilePath* current_directory) {
+  // We should have enough room for the shortest command (min_message_size)
+  // and also be a multiple of wchar_t bytes. The shortest command
+  // possible is L"START\0\0" (empty current directory and command line).
+  static const int min_message_size = 7;
+  if (cds->cbData < min_message_size * sizeof(wchar_t) ||
+      cds->cbData % sizeof(wchar_t) != 0) {
+    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
+    return false;
+  }
+
+  // We split the string into 4 parts on NULLs.
+  DCHECK(cds->lpData);
+  const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
+                         cds->cbData / sizeof(wchar_t));
+  const std::wstring::size_type first_null = msg.find_first_of(L'\0');
+  if (first_null == 0 || first_null == std::wstring::npos) {
+    // no NULL byte, don't know what to do
+    LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length() <<
+      ", first null = " << first_null;
+    return false;
+  }
+
+  // Decode the command, which is everything until the first NULL.
+  if (msg.substr(0, first_null) == L"START") {
+    // Another instance is starting parse the command line & do what it would
+    // have done.
+    VLOG(1) << "Handling STARTUP request from another process";
+    const std::wstring::size_type second_null =
+        msg.find_first_of(L'\0', first_null + 1);
+    if (second_null == std::wstring::npos ||
+        first_null == msg.length() - 1 || second_null == msg.length()) {
+      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
+        "parts separated by NULLs";
+      return false;
+    }
+
+    // Get current directory.
+    *current_directory = base::FilePath(msg.substr(first_null + 1,
+                                                   second_null - first_null));
+
+    const std::wstring::size_type third_null =
+        msg.find_first_of(L'\0', second_null + 1);
+    if (third_null == std::wstring::npos ||
+        third_null == msg.length()) {
+      LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
+        "parts separated by NULLs";
+    }
+
+    // Get command line.
+    const std::wstring cmd_line =
+        msg.substr(second_null + 1, third_null - second_null);
+    *parsed_command_line = base::CommandLine::FromString(cmd_line);
+    return true;
+  }
+  return false;
+}
+
+bool ProcessLaunchNotification(
+    const ProcessSingleton::NotificationCallback& notification_callback,
+    UINT message,
+    WPARAM wparam,
+    LPARAM lparam,
+    LRESULT* result) {
+  if (message != WM_COPYDATA)
+    return false;
+
+  // Handle the WM_COPYDATA message from another process.
+  const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
+
+  base::CommandLine parsed_command_line(base::CommandLine::NO_PROGRAM);
+  base::FilePath current_directory;
+  if (!ParseCommandLine(cds, &parsed_command_line, &current_directory)) {
+    *result = TRUE;
+    return true;
+  }
+
+  *result = notification_callback.Run(parsed_command_line, current_directory) ?
+      TRUE : FALSE;
+  return true;
+}
+
+// Returns true if Chrome needs to be relaunched into Windows 8 immersive mode.
+// Following conditions apply:-
+// 1. Windows 8 or greater.
+// 2. Not in Windows 8 immersive mode.
+// 3. Chrome is default browser.
+// 4. Process integrity level is not high.
+// 5. The profile data directory is the default directory.
+// 6. Last used mode was immersive/machine is a tablet.
+// TODO(ananta)
+// Move this function to a common place as the Windows 8 delegate_execute
+// handler can possibly use this.
+bool ShouldLaunchInWindows8ImmersiveMode(const base::FilePath& user_data_dir) {
+  // Returning false from this function doesn't mean we don't launch immersive
+  // mode in Aura. This function is specifically called in case when we need
+  // to relaunch desktop launched chrome into immersive mode through 'relaunch'
+  // menu. In case of Aura, we will use delegate_execute to do the relaunch.
+  return false;
+}
+
+bool DisplayShouldKillMessageBox() {
+  return chrome::ShowMessageBox(
+             NULL, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
+             l10n_util::GetStringUTF16(IDS_BROWSER_HUNGBROWSER_MESSAGE),
+             chrome::MESSAGE_BOX_TYPE_QUESTION) !=
+         chrome::MESSAGE_BOX_RESULT_NO;
+}
+
+}  // namespace
+
+// Microsoft's Softricity virtualization breaks the sandbox processes.
+// So, if we detect the Softricity DLL we use WMI Win32_Process.Create to
+// break out of the virtualization environment.
+// http://code.google.com/p/chromium/issues/detail?id=43650
+bool ProcessSingleton::EscapeVirtualization(
+    const base::FilePath& user_data_dir) {
+  if (::GetModuleHandle(L"sftldr_wow64.dll") ||
+      ::GetModuleHandle(L"sftldr.dll")) {
+    int process_id;
+    if (!installer::WMIProcess::Launch(::GetCommandLineW(), &process_id))
+      return false;
+    is_virtualized_ = true;
+    // The new window was spawned from WMI, and won't be in the foreground.
+    // So, first we sleep while the new chrome.exe instance starts (because
+    // WaitForInputIdle doesn't work here). Then we poll for up to two more
+    // seconds and make the window foreground if we find it (or we give up).
+    HWND hwnd = 0;
+    ::Sleep(90);
+    for (int tries = 200; tries; --tries) {
+      hwnd = chrome::FindRunningChromeWindow(user_data_dir);
+      if (hwnd) {
+        ::SetForegroundWindow(hwnd);
+        break;
+      }
+      ::Sleep(10);
+    }
+    return true;
+  }
+  return false;
+}
+
+ProcessSingleton::ProcessSingleton(
+    const base::FilePath& user_data_dir,
+    const NotificationCallback& notification_callback)
+    : notification_callback_(notification_callback),
+      is_virtualized_(false),
+      lock_file_(INVALID_HANDLE_VALUE),
+      user_data_dir_(user_data_dir),
+      should_kill_remote_process_callback_(
+          base::Bind(&DisplayShouldKillMessageBox)) {
+}
+
+ProcessSingleton::~ProcessSingleton() {
+  if (lock_file_ != INVALID_HANDLE_VALUE)
+    ::CloseHandle(lock_file_);
+}
+
+// Code roughly based on Mozilla.
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
+  if (is_virtualized_)
+    return PROCESS_NOTIFIED;  // We already spawned the process in this case.
+  if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) {
+    return LOCK_ERROR;
+  } else if (!remote_window_) {
+    return PROCESS_NONE;
+  }
+
+  switch (chrome::AttemptToNotifyRunningChrome(remote_window_, false)) {
+    case chrome::NOTIFY_SUCCESS:
+      return PROCESS_NOTIFIED;
+    case chrome::NOTIFY_FAILED:
+      remote_window_ = NULL;
+      return PROCESS_NONE;
+    case chrome::NOTIFY_WINDOW_HUNG:
+      // Fall through and potentially terminate the hung browser.
+      break;
+  }
+
+  DWORD process_id = 0;
+  DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
+  if (!thread_id || !process_id) {
+    remote_window_ = NULL;
+    return PROCESS_NONE;
+  }
+  base::Process process = base::Process::Open(process_id);
+
+  // The window is hung. Scan for every window to find a visible one.
+  bool visible_window = false;
+  ::EnumThreadWindows(thread_id,
+                      &BrowserWindowEnumeration,
+                      reinterpret_cast<LPARAM>(&visible_window));
+
+  // If there is a visible browser window, ask the user before killing it.
+  if (visible_window && !should_kill_remote_process_callback_.Run()) {
+    // The user denied. Quit silently.
+    return PROCESS_NOTIFIED;
+  }
+
+  // Time to take action. Kill the browser process.
+  process.Terminate(content::RESULT_CODE_HUNG, true);
+  remote_window_ = NULL;
+  return PROCESS_NONE;
+}
+
+ProcessSingleton::NotifyResult
+ProcessSingleton::NotifyOtherProcessOrCreate() {
+  ProcessSingleton::NotifyResult result = PROCESS_NONE;
+  if (!Create()) {
+    result = NotifyOtherProcess();
+    if (result == PROCESS_NONE)
+      result = PROFILE_IN_USE;
+  } else {
+    g_browser_process->platform_part()->PlatformSpecificCommandLineProcessing(
+        *base::CommandLine::ForCurrentProcess());
+  }
+  return result;
+}
+
+// Look for a Chrome instance that uses the same profile directory. If there
+// isn't one, create a message window with its title set to the profile
+// directory path.
+bool ProcessSingleton::Create() {
+  static const wchar_t kMutexName[] = L"Local\\ChromeProcessSingletonStartup!";
+  static const wchar_t kMetroActivationEventName[] =
+      L"Local\\ChromeProcessSingletonStartupMetroActivation!";
+
+  remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
+  if (!remote_window_ && !EscapeVirtualization(user_data_dir_)) {
+    // Make sure we will be the one and only process creating the window.
+    // We use a named Mutex since we are protecting against multi-process
+    // access. As documented, it's clearer to NOT request ownership on creation
+    // since it isn't guaranteed we will get it. It is better to create it
+    // without ownership and explicitly get the ownership afterward.
+    base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName));
+    if (!only_me.IsValid()) {
+      DPLOG(FATAL) << "CreateMutex failed";
+      return false;
+    }
+
+    AutoLockMutex auto_lock_only_me(only_me.Get());
+
+    // We now own the mutex so we are the only process that can create the
+    // window at this time, but we must still check if someone created it
+    // between the time where we looked for it above and the time the mutex
+    // was given to us.
+    remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
+
+
+    // In Win8+, a new Chrome process launched in Desktop mode may need to be
+    // transmuted into Metro Chrome (see ShouldLaunchInWindows8ImmersiveMode for
+    // heuristics). To accomplish this, the current Chrome activates Metro
+    // Chrome, releases the startup mutex, and waits for metro Chrome to take
+    // the singleton. From that point onward, the command line for this Chrome
+    // process will be sent to Metro Chrome by the usual channels.
+    if (!remote_window_ && base::win::GetVersion() >= base::win::VERSION_WIN8 &&
+        !base::win::IsMetroProcess()) {
+      // |metro_activation_event| is created right before activating a Metro
+      // Chrome (note that there can only be one Metro Chrome process; by OS
+      // design); all following Desktop processes will then wait for this event
+      // to be signaled by Metro Chrome which will do so as soon as it grabs
+      // this singleton (should any of the waiting processes timeout waiting for
+      // the signal they will try to grab the singleton for themselves which
+      // will result in a forced Desktop Chrome launch in the worst case).
+      base::win::ScopedHandle metro_activation_event(
+          ::OpenEvent(SYNCHRONIZE, FALSE, kMetroActivationEventName));
+      if (!metro_activation_event.IsValid() &&
+          ShouldLaunchInWindows8ImmersiveMode(user_data_dir_)) {
+        // No Metro activation is under way, but the desire is to launch in
+        // Metro mode: activate and rendez-vous with the activated process.
+        metro_activation_event.Set(
+            ::CreateEvent(NULL, TRUE, FALSE, kMetroActivationEventName));
+        if (!chrome::ActivateMetroChrome()) {
+          // Failed to launch immersive Chrome, default to launching on Desktop.
+          LOG(ERROR) << "Failed to launch immersive chrome";
+          metro_activation_event.Close();
+        }
+      }
+
+      if (metro_activation_event.IsValid()) {
+        // Release |only_me| (to let Metro Chrome grab this singleton) and wait
+        // until the event is signaled (i.e. Metro Chrome was successfully
+        // activated). Ignore timeout waiting for |metro_activation_event|.
+        {
+          AutoUnlockMutex auto_unlock_only_me(only_me.Get());
+
+          DWORD result = ::WaitForSingleObject(metro_activation_event.Get(),
+                                               kMetroChromeActivationTimeoutMs);
+          DPCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
+              << "Result = " << result;
+        }
+
+        // Check if this singleton was successfully grabbed by another process
+        // (hopefully Metro Chrome). Failing to do so, this process will grab
+        // the singleton and launch in Desktop mode.
+        remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
+      }
+    }
+
+    if (!remote_window_) {
+      // We have to make sure there is no Chrome instance running on another
+      // machine that uses the same profile.
+      base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile);
+      lock_file_ = ::CreateFile(lock_file_path.value().c_str(),
+                                GENERIC_WRITE,
+                                FILE_SHARE_READ,
+                                NULL,
+                                CREATE_ALWAYS,
+                                FILE_ATTRIBUTE_NORMAL |
+                                FILE_FLAG_DELETE_ON_CLOSE,
+                                NULL);
+      DWORD error = ::GetLastError();
+      LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
+          error == ERROR_ALREADY_EXISTS) << "Lock file exists but is writable.";
+      LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
+          << "Lock file can not be created! Error code: " << error;
+
+      if (lock_file_ != INVALID_HANDLE_VALUE) {
+        // Set the window's title to the path of our user data directory so
+        // other Chrome instances can decide if they should forward to us.
+        bool result = window_.CreateNamed(
+            base::Bind(&ProcessLaunchNotification, notification_callback_),
+            user_data_dir_.value());
+        CHECK(result && window_.hwnd());
+      }
+
+      if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+        // Make sure no one is still waiting on Metro activation whether it
+        // succeeded (i.e., this is the Metro process) or failed.
+        base::win::ScopedHandle metro_activation_event(
+            ::OpenEvent(EVENT_MODIFY_STATE, FALSE, kMetroActivationEventName));
+        if (metro_activation_event.IsValid())
+          ::SetEvent(metro_activation_event.Get());
+      }
+    }
+  }
+
+  return window_.hwnd() != NULL;
+}
+
+void ProcessSingleton::Cleanup() {
+}
+
+void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
+    const ShouldKillRemoteProcessCallback& display_dialog_callback) {
+  should_kill_remote_process_callback_ = display_dialog_callback;
+}