diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-21 01:18:37 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-21 01:18:37 +0000 |
commit | 9f20a6d0e6153489efe035c860f249c7cbc28890 (patch) | |
tree | 27fc986ae9f9600d12268ea043156048400712d8 /chrome/browser | |
parent | 0a1f310d964e67756c8316330ffb090048c9ae82 (diff) | |
download | chromium_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.cc | 21 | ||||
-rw-r--r-- | chrome/browser/process_singleton.h | 14 | ||||
-rw-r--r-- | chrome/browser/process_singleton_linux.cc | 213 | ||||
-rw-r--r-- | chrome/browser/process_singleton_linux_uitest.cc | 88 | ||||
-rw-r--r-- | chrome/browser/process_singleton_mac.cc | 8 | ||||
-rw-r--r-- | chrome/browser/process_singleton_win.cc | 21 |
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, ¤t_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 |