summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authormattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-21 01:18:37 +0000
committermattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-21 01:18:37 +0000
commit9f20a6d0e6153489efe035c860f249c7cbc28890 (patch)
tree27fc986ae9f9600d12268ea043156048400712d8 /chrome/browser
parent0a1f310d964e67756c8316330ffb090048c9ae82 (diff)
downloadchromium_src-9f20a6d0e6153489efe035c860f249c7cbc28890.zip
chromium_src-9f20a6d0e6153489efe035c860f249c7cbc28890.tar.gz
chromium_src-9f20a6d0e6153489efe035c860f249c7cbc28890.tar.bz2
Make ProcessSingletonLinux check the hostname to avoid multiple uses of a profile over NFS.
In order to avoid the singleton socket filename from exceeding the max socket name length, the socket is just named "SingletonSocket" and a new file "SingletonLock" is used for the hostname&pid. BUG=17549 TEST=see bug Review URL: http://codereview.chromium.org/174041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23930 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/browser_main.cc21
-rw-r--r--chrome/browser/process_singleton.h14
-rw-r--r--chrome/browser/process_singleton_linux.cc213
-rw-r--r--chrome/browser/process_singleton_linux_uitest.cc88
-rw-r--r--chrome/browser/process_singleton_mac.cc8
-rw-r--r--chrome/browser/process_singleton_win.cc21
6 files changed, 255 insertions, 110 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index d6dd7e2..bb3d1c3 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -588,12 +588,23 @@ int BrowserMain(const MainFunctionParams& parameters) {
return FirstRun::ImportNow(profile, parsed_command_line);
// When another process is running, use it instead of starting us.
- if (process_singleton.NotifyOtherProcess()) {
+ switch (process_singleton.NotifyOtherProcess()) {
+ case ProcessSingleton::PROCESS_NONE:
+ // No process already running, fall through to starting a new one.
+ break;
+
+ case ProcessSingleton::PROCESS_NOTIFIED:
#if defined(OS_LINUX)
- printf("%s\n", base::SysWideToNativeMB(
- l10n_util::GetString(IDS_USED_EXISTING_BROWSER)).c_str());
+ printf("%s\n", base::SysWideToNativeMB(
+ l10n_util::GetString(IDS_USED_EXISTING_BROWSER)).c_str());
#endif
- return ResultCodes::NORMAL_EXIT;
+ return ResultCodes::NORMAL_EXIT;
+
+ case ProcessSingleton::PROFILE_IN_USE:
+ return ResultCodes::PROFILE_IN_USE;
+
+ default:
+ NOTREACHED();
}
// Do the tasks if chrome has been upgraded while it was last running.
@@ -806,6 +817,8 @@ int BrowserMain(const MainFunctionParams& parameters) {
}
}
+ process_singleton.Cleanup();
+
Platform::WillTerminate();
if (metrics)
diff --git a/chrome/browser/process_singleton.h b/chrome/browser/process_singleton.h
index ed572fe..122618f 100644
--- a/chrome/browser/process_singleton.h
+++ b/chrome/browser/process_singleton.h
@@ -31,6 +31,12 @@
class ProcessSingleton : public NonThreadSafe {
public:
+ enum NotifyResult {
+ PROCESS_NONE,
+ PROCESS_NOTIFIED,
+ PROFILE_IN_USE,
+ };
+
explicit ProcessSingleton(const FilePath& user_data_dir);
~ProcessSingleton();
@@ -41,11 +47,14 @@ class ProcessSingleton : public NonThreadSafe {
// TODO(brettw): this will not handle all cases. If two process start up too
// close to each other, the Create() might not yet have happened for the
// first one, so this function won't find it.
- bool NotifyOtherProcess();
+ NotifyResult NotifyOtherProcess();
// Sets ourself up as the singleton instance.
void Create();
+ // Clear any lock state during shutdown.
+ void Cleanup();
+
// Blocks the dispatch of CopyData messages. foreground_window refers
// to the window that should be set to the foreground if a CopyData message
// is received while the ProcessSingleton is locked.
@@ -101,6 +110,9 @@ class ProcessSingleton : public NonThreadSafe {
// Path in file system to the socket.
FilePath socket_path_;
+ // Path in file system to the lock.
+ FilePath lock_path_;
+
// Helper class for linux specific messages. LinuxWatcher is ref counted
// because it posts messages between threads.
class LinuxWatcher;
diff --git a/chrome/browser/process_singleton_linux.cc b/chrome/browser/process_singleton_linux.cc
index 124529b..97e25b5 100644
--- a/chrome/browser/process_singleton_linux.cc
+++ b/chrome/browser/process_singleton_linux.cc
@@ -8,15 +8,17 @@
// directory and second process command line flags. The second process then
// exits.
//
-// The socket file's name contains the process id of chrome's browser process,
-// eg. "SingletonSocket-9156". A symbol link named "SingletonSocket" will be
-// created and pointed to the real socket file, so they would look like:
+// 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.
//
-// SingletonSocket -> SingletonSocket-9156
-// SingletonSocket-9156
-//
-// So that the socket file can be connected through "SingletonSocket" and the
-// process id can also be retrieved from it by calling readlink().
+// 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
@@ -41,6 +43,7 @@
#include <set>
#include <string>
+#include "app/l10n_util.h"
#include "base/base_paths.h"
#include "base/basictypes.h"
#include "base/command_line.h"
@@ -51,6 +54,7 @@
#include "base/process_util.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
#include "base/time.h"
#include "base/timer.h"
#include "chrome/browser/browser_init.h"
@@ -60,6 +64,9 @@
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
+#include "grit/chromium_strings.h"
+#include "grit/generated_resources.h"
+#include "net/base/net_util.h"
const int ProcessSingleton::kTimeoutInSeconds;
@@ -72,6 +79,8 @@ const char kTokenDelimiter = '\0';
const int kMaxMessageLength = 32 * 1024;
const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
+const char kLockDelimiter = '-';
+
// Set a file descriptor to be non-blocking.
// Return 0 on success, -1 on failure.
int SetNonBlocking(int fd) {
@@ -201,13 +210,7 @@ std::string ReadLink(const std::string& path) {
ssize_t len = readlink(path.c_str(), buf, PATH_MAX);
if (len > 0) {
buf[len] = '\0';
- FilePath real_path(buf);
- // If it's not an absolute path, then it's necessary to prepend the
- // original path's dirname.
- if (!real_path.IsAbsolute()) {
- real_path = FilePath(path).DirName().Append(real_path);
- }
- return real_path.value();
+ return std::string(buf);
} else {
LOG(ERROR) << "readlink(" << path << ") failed: " << strerror(errno);
}
@@ -216,50 +219,89 @@ std::string ReadLink(const std::string& path) {
return std::string();
}
-// Unlink a socket path. If the path is a symbol link, then the symbol link
-// and the real path referenced by the symbol link will be unlinked together.
-bool UnlinkSocketPath(const std::string& path) {
- std::string real_path = ReadLink(path);
-
- bool ret = true;
- if (real_path.length())
- ret = UnlinkSocketPath(real_path);
-
+// Unlink a path. Return true on success.
+bool UnlinkPath(const std::string& path) {
int rv = unlink(path.c_str());
if (rv < 0)
DCHECK_EQ(errno, ENOENT);
- return rv == 0 && ret;
+ return rv == 0;
}
-// Extract the process's pid from a symbol link path and kill it.
-// The pid will be appended to the end of path with a preceding dash, such as:
-// .../SingletonSocket-1234
-void KillProcessBySocketPath(const std::string& path) {
+// Extract the hostname and pid from the lock symlink.
+std::string ParseLockPath(const std::string& path,
+ std::string* hostname,
+ int* pid) {
std::string real_path = ReadLink(path);
+ std::string::size_type pos = real_path.rfind('-');
+
+ // 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 "";
+ }
- // If the path is not a symbol link, try to extract pid from the path itself.
- if (real_path.empty())
- real_path = path;
-
- // Only extract pid from the base name, to avoid finding wrong value from its
- // parent path name.
- std::string base_name = FilePath(real_path).BaseName().value();
- DCHECK(base_name.length());
-
- std::string::size_type pos = base_name.rfind('-');
- if (pos != std::string::npos) {
- std::string pid_str = base_name.substr(pos + 1);
- int pid;
- if (StringToInt(pid_str, &pid)) {
- // TODO(james.su@gmail.com): Is SIGKILL ok?
- int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
- DCHECK_EQ(0, rv) << "Error killing process:" << strerror(errno);
- return;
- }
+ *hostname = real_path.substr(0, pos);
+
+ const std::string& pid_str = real_path.substr(pos + 1);
+ if (!StringToInt(pid_str, pid))
+ *pid = -1;
+
+ return real_path;
+}
+
+void DisplayProfileInUseError(const std::string& lock_path,
+ const std::string& hostname,
+ int pid) {
+ // TODO(mattm): display in a dialog.
+ std::wstring error = l10n_util::GetStringF(IDS_PROFILE_IN_USE_LINUX,
+ IntToWString(pid),
+ ASCIIToWide(hostname),
+ base::SysNativeMBToWide(lock_path),
+ l10n_util::GetString(IDS_PRODUCT_NAME));
+ LOG(ERROR) << base::SysWideToNativeMB(error).c_str();
+}
+
+// Check if the lock is on a different host. If so, return false. If not,
+// unlink the lock file and return true.
+bool CheckLockHostnameAndCleanup(const std::string& path) {
+ std::string hostname;
+ int pid;
+ ParseLockPath(path, &hostname, &pid);
+
+ if (!hostname.empty() && hostname != net::GetHostName()){
+ DisplayProfileInUseError(path, hostname, pid);
+ return false;
}
+ UnlinkPath(path);
+ return true;
+}
+
+// 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 on a different host, return false.
+bool KillProcessByLockPath(const std::string& path) {
+ std::string hostname;
+ int pid;
+ ParseLockPath(path, &hostname, &pid);
- LOG(ERROR) << "Failed to extract pid from path: " << real_path;
+ if (!hostname.empty() && hostname != net::GetHostName()) {
+ DisplayProfileInUseError(path, hostname, pid);
+ return false;
+ }
+ UnlinkPath(path);
+
+ if (pid >= 0) {
+ // TODO(james.su@gmail.com): Is SIGKILL ok?
+ int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
+ DCHECK_EQ(0, rv) << "Error killing process:" << strerror(errno);
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to extract pid from path: " << path;
+ return true;
}
// A helper class to close a socket automatically.
@@ -570,12 +612,13 @@ ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
foreground_window_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) {
socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
+ lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
}
ProcessSingleton::~ProcessSingleton() {
}
-bool ProcessSingleton::NotifyOtherProcess() {
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
int socket;
sockaddr_un addr;
SetupSocket(socket_path_.value(), &socket, &addr);
@@ -587,8 +630,15 @@ bool ProcessSingleton::NotifyOtherProcess() {
int ret = HANDLE_EINTR(connect(socket,
reinterpret_cast<sockaddr*>(&addr),
sizeof(addr)));
- if (ret < 0)
- return false; // Tell the caller there's nobody to notify.
+ if (ret < 0) {
+ // TODO(mattm): there is a bit of a race here if another instance on the
+ // same host is in Create() and has created the lock but not attached to the
+ // socket. Our CheckLockHostnameAndCleanup call will clean up their lock
+ // and allow us to create a new one.
+ if (!CheckLockHostnameAndCleanup(lock_path_.value()))
+ return PROFILE_IN_USE;
+ return PROCESS_NONE; // Tell the caller there's nobody to notify.
+ }
timeval timeout = {20, 0};
setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
@@ -600,7 +650,7 @@ bool ProcessSingleton::NotifyOtherProcess() {
FilePath current_dir;
if (!PathService::Get(base::DIR_CURRENT, &current_dir))
- return false;
+ return PROCESS_NONE;
to_send.append(current_dir.value());
const std::vector<std::string>& argv =
@@ -614,8 +664,9 @@ bool ProcessSingleton::NotifyOtherProcess() {
// Send the message
if (!WriteToSocket(socket, to_send.data(), to_send.length())) {
// Try to kill the other process, because it might have been dead.
- KillProcessBySocketPath(socket_path_.value());
- return false;
+ if (!KillProcessByLockPath(lock_path_.value()))
+ return PROFILE_IN_USE;
+ return PROCESS_NONE;
}
if (shutdown(socket, SHUT_WR) < 0)
@@ -629,42 +680,54 @@ bool ProcessSingleton::NotifyOtherProcess() {
// Failed to read ACK, the other process might have been frozen.
if (len <= 0) {
- KillProcessBySocketPath(socket_path_.value());
- return false;
+ if (!KillProcessByLockPath(lock_path_.value()))
+ 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 false;
+ return PROCESS_NONE;
} else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) {
// Assume the other process is handling the request.
- return true;
+ return PROCESS_NOTIFIED;
}
NOTREACHED() << "The other process returned unknown message: " << buf;
- return true;
+ return PROCESS_NOTIFIED;
}
void ProcessSingleton::Create() {
int sock;
sockaddr_un addr;
- // Append the process id to the socket path, so that other process can find it
- // out.
- std::string path = StringPrintf(
- "%s-%u", socket_path_.value().c_str(), base::GetCurrentProcId());
- SetupSocket(path, &sock, &addr);
+ // The symlink lock is pointed to the hostname and process id, so other
+ // processes can find it out.
+ std::string symlink_content = StringPrintf(
+ "%s%c%u",
+ net::GetHostName().c_str(),
+ kLockDelimiter,
+ base::GetCurrentProcId());
+
+ // Create symbol link before binding the socket, to ensure only one instance
+ // can have the socket open.
+ if (symlink(symlink_content.c_str(), lock_path_.value().c_str()) < 0) {
+ // 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(lock_path_.value()) != symlink_content) {
+ // If we failed to create the lock, most likely another instance won the
+ // startup race.
+ // TODO(mattm): If the other instance is on the same host, we could try
+ // to notify it rather than just failing.
+ LOG(FATAL) << "Failed to create SingletonLock: " << strerror(saved_errno);
+ }
+ }
- UnlinkSocketPath(socket_path_.value());
+ SetupSocket(socket_path_.value(), &sock, &addr);
- // Create symbol link before binding the socket, so that the socket file can
- // always be reached and removed by another process.
- // The symbol link only contains the filename part of the socket file, so that
- // the whole config directory can be moved without breaking the symbol link.
- std::string symlink_content = FilePath(path).BaseName().value();
- if (symlink(symlink_content.c_str(), socket_path_.value().c_str()) < 0)
- NOTREACHED() << "Failed to create symbol link: " << strerror(errno);
+ UnlinkPath(socket_path_.value());
if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
LOG(ERROR) << "bind() failed: " << strerror(errno);
@@ -689,3 +752,7 @@ void ProcessSingleton::Create() {
&ProcessSingleton::LinuxWatcher::StartListening,
sock));
}
+
+void ProcessSingleton::Cleanup() {
+ UnlinkPath(lock_path_.value());
+}
diff --git a/chrome/browser/process_singleton_linux_uitest.cc b/chrome/browser/process_singleton_linux_uitest.cc
index 07220f6..7f2b90c 100644
--- a/chrome/browser/process_singleton_linux_uitest.cc
+++ b/chrome/browser/process_singleton_linux_uitest.cc
@@ -11,6 +11,7 @@
#include <vector>
#include <string>
+#include "base/eintr_wrapper.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
@@ -24,18 +25,30 @@
#include "testing/gtest/include/gtest/gtest.h"
class ProcessSingletonLinuxTest : public UITest {
+ public:
+ virtual void SetUp() {
+ UITest::SetUp();
+ old_argv_ = CommandLine::ForCurrentProcess()->argv();
+ }
+
+ virtual void TearDown() {
+ if (!old_argv_.empty()) {
+ CommandLine::Reset();
+ CommandLine::Init(old_argv_);
+ }
+ UITest::TearDown();
+ }
+
protected:
// A helper method to call ProcessSingleton::NotifyOtherProcess().
// |url| will be added to CommandLine for current process, so that it can be
// sent to browser process by ProcessSingleton::NotifyOtherProcess().
- void NotifyOtherProcess(const std::string& url, bool expect_result) {
+ ProcessSingleton::NotifyResult NotifyOtherProcess(const std::string& url) {
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- std::vector<std::string> old_argv =
- CommandLine::ForCurrentProcess()->argv();
std::vector<std::string> argv;
- argv.push_back(old_argv[0]);
+ argv.push_back(old_argv_[0]);
argv.push_back(url);
CommandLine::Reset();
@@ -43,11 +56,10 @@ class ProcessSingletonLinuxTest : public UITest {
ProcessSingleton process_singleton(user_data_dir);
- if (expect_result)
- EXPECT_TRUE(process_singleton.NotifyOtherProcess());
- else
- EXPECT_FALSE(process_singleton.NotifyOtherProcess());
+ return process_singleton.NotifyOtherProcess();
}
+
+ std::vector<std::string> old_argv_;
};
// Test if the socket file and symbol link created by ProcessSingletonLinux
@@ -55,21 +67,22 @@ class ProcessSingletonLinuxTest : public UITest {
// initiated by UITest. So we just test against this existing object.
TEST_F(ProcessSingletonLinuxTest, CheckSocketFile) {
FilePath user_data_dir;
- FilePath path;
+ FilePath socket_path;
+ FilePath lock_path;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- path = user_data_dir.Append(chrome::kSingletonSocketFilename);
+ socket_path = user_data_dir.Append(chrome::kSingletonSocketFilename);
+ lock_path = user_data_dir.Append(chrome::kSingletonLockFilename);
struct stat statbuf;
- ASSERT_EQ(0, lstat(path.value().c_str(), &statbuf));
+ ASSERT_EQ(0, lstat(lock_path.value().c_str(), &statbuf));
ASSERT_TRUE(S_ISLNK(statbuf.st_mode));
char buf[PATH_MAX + 1];
- ssize_t len = readlink(path.value().c_str(), buf, PATH_MAX);
+ ssize_t len = readlink(lock_path.value().c_str(), buf, PATH_MAX);
ASSERT_GT(len, 0);
buf[len] = '\0';
- path = user_data_dir.Append(buf);
- ASSERT_EQ(0, lstat(path.value().c_str(), &statbuf));
+ ASSERT_EQ(0, lstat(socket_path.value().c_str(), &statbuf));
ASSERT_TRUE(S_ISSOCK(statbuf.st_mode));
}
@@ -79,7 +92,7 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessSuccess) {
std::string url("about:blank");
int original_tab_count = GetTabCount();
- NotifyOtherProcess(url, true);
+ EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, NotifyOtherProcess(url));
EXPECT_EQ(original_tab_count + 1, GetTabCount());
EXPECT_EQ(url, GetActiveTabURL().spec());
}
@@ -88,21 +101,54 @@ TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessSuccess) {
TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessFailure) {
base::ProcessId pid = ChromeBrowserProcessId(user_data_dir());
- ASSERT_GT(pid, 1);
+ ASSERT_GE(pid, 1);
// Block the browser process, then it'll be killed by
// ProcessSingleton::NotifyOtherProcess().
kill(pid, SIGSTOP);
- // Wait for a while to make sure the browser process is actually stopped.
+ // Wait to make sure the browser process is actually stopped.
// It's necessary when running with valgrind.
- sleep(1);
+ HANDLE_EINTR(waitpid(pid, 0, WUNTRACED));
std::string url("about:blank");
- NotifyOtherProcess(url, false);
+ EXPECT_EQ(ProcessSingleton::PROCESS_NONE, NotifyOtherProcess(url));
// Wait for a while to make sure the browser process is actually killed.
- sleep(1);
+ EXPECT_FALSE(CrashAwareSleep(1000));
+}
- EXPECT_FALSE(IsBrowserRunning());
+// Test that we can still notify a process on the same host even after the
+// hostname changed.
+TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessHostChanged) {
+ FilePath lock_path = user_data_dir().Append(chrome::kSingletonLockFilename);
+ EXPECT_EQ(0, unlink(lock_path.value().c_str()));
+ EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path.value().c_str()));
+
+ int original_tab_count = GetTabCount();
+
+ std::string url("about:blank");
+ EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, NotifyOtherProcess(url));
+ EXPECT_EQ(original_tab_count + 1, GetTabCount());
+ EXPECT_EQ(url, GetActiveTabURL().spec());
+}
+
+// Test that we fail when lock says process is on another host and we can't
+// notify it over the socket.
+TEST_F(ProcessSingletonLinuxTest, NotifyOtherProcessDifferingHost) {
+ base::ProcessId pid = ChromeBrowserProcessId(user_data_dir());
+
+ ASSERT_GE(pid, 1);
+
+ // Kill the browser process, so that it does not respond on the socket.
+ kill(pid, SIGKILL);
+ // Wait for a while to make sure the browser process is actually killed.
+ EXPECT_FALSE(CrashAwareSleep(1000));
+
+ FilePath lock_path = user_data_dir().Append(chrome::kSingletonLockFilename);
+ EXPECT_EQ(0, unlink(lock_path.value().c_str()));
+ EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path.value().c_str()));
+
+ std::string url("about:blank");
+ EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcess(url));
}
diff --git a/chrome/browser/process_singleton_mac.cc b/chrome/browser/process_singleton_mac.cc
index c4884db..c1edbb5 100644
--- a/chrome/browser/process_singleton_mac.cc
+++ b/chrome/browser/process_singleton_mac.cc
@@ -27,11 +27,15 @@ ProcessSingleton::~ProcessSingleton() {
// This space intentionally left blank.
}
-bool ProcessSingleton::NotifyOtherProcess() {
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
// This space intentionally left blank.
- return false;
+ return PROCESS_NONE;
}
void ProcessSingleton::Create() {
// This space intentionally left blank.
}
+
+void ProcessSingleton::Cleanup() {
+ // This space intentionally left blank.
+}
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 74e1d51..3c48bb8 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -51,16 +51,16 @@ ProcessSingleton::~ProcessSingleton() {
}
}
-bool ProcessSingleton::NotifyOtherProcess() {
+ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
if (!remote_window_)
- return false;
+ return PROCESS_NONE;
// Found another window, send our command line to it
// format is "START\0<<<current directory>>>\0<<<commandline>>>".
std::wstring to_send(L"START\0", 6); // want the NULL in the string.
std::wstring cur_dir;
if (!PathService::Get(base::DIR_CURRENT, &cur_dir))
- return false;
+ return PROCESS_NONE;
to_send.append(cur_dir);
to_send.append(L"\0", 1); // Null separator.
to_send.append(GetCommandLineW());
@@ -73,7 +73,7 @@ bool ProcessSingleton::NotifyOtherProcess() {
// It is possible that the process owning this window may have died by now.
if (!thread_id || !process_id) {
remote_window_ = NULL;
- return false;
+ return PROCESS_NONE;
}
AllowSetForegroundWindow(process_id);
@@ -93,15 +93,15 @@ bool ProcessSingleton::NotifyOtherProcess() {
// It is possible that the process owning this window may have died by now.
if (!result) {
remote_window_ = NULL;
- return false;
+ return PROCESS_NONE;
}
- return true;
+ return PROCESS_NOTIFIED;
}
// It is possible that the process owning this window may have died by now.
if (!IsWindow(remote_window_)) {
remote_window_ = NULL;
- return false;
+ return PROCESS_NONE;
}
// The window is hung. Scan for every window to find a visible one.
@@ -117,14 +117,14 @@ bool ProcessSingleton::NotifyOtherProcess() {
if (IDYES != win_util::MessageBox(NULL, text, caption,
MB_YESNO | MB_ICONSTOP | MB_TOPMOST)) {
// The user denied. Quit silently.
- return true;
+ return PROCESS_NOTIFIED;
}
}
// Time to take action. Kill the browser process.
base::KillProcessById(process_id, ResultCodes::HUNG, true);
remote_window_ = NULL;
- return false;
+ return PROCESS_NONE;
}
// For windows, there is no need to call Create() since the call is made in
@@ -157,6 +157,9 @@ void ProcessSingleton::Create() {
win_util::SetWindowUserData(window_, this);
}
+void ProcessSingleton::Cleanup() {
+}
+
LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) {
// If locked, it means we are not ready to process this message because
// we are probably in a first run critical phase. We must do this before