Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: chrome/browser/process_singleton_posix.cc

Issue 218883008: Use process_singleton_linux on Mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Handle old SingletonLock Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // On Linux, when the user tries to launch a second copy of chrome, we check 5 // On Linux, when the user tries to launch a second copy of chrome, we check
6 // for a socket in the user's profile directory. If the socket file is open we 6 // for a socket in the user's profile directory. If the socket file is open we
7 // send a message to the first chrome browser process with the current 7 // send a message to the first chrome browser process with the current
8 // directory and second process command line flags. The second process then 8 // directory and second process command line flags. The second process then
9 // exits. 9 // exits.
10 // 10 //
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 #include "base/sequenced_task_runner_helpers.h" 67 #include "base/sequenced_task_runner_helpers.h"
68 #include "base/stl_util.h" 68 #include "base/stl_util.h"
69 #include "base/strings/string_number_conversions.h" 69 #include "base/strings/string_number_conversions.h"
70 #include "base/strings/string_split.h" 70 #include "base/strings/string_split.h"
71 #include "base/strings/stringprintf.h" 71 #include "base/strings/stringprintf.h"
72 #include "base/strings/sys_string_conversions.h" 72 #include "base/strings/sys_string_conversions.h"
73 #include "base/strings/utf_string_conversions.h" 73 #include "base/strings/utf_string_conversions.h"
74 #include "base/threading/platform_thread.h" 74 #include "base/threading/platform_thread.h"
75 #include "base/time/time.h" 75 #include "base/time/time.h"
76 #include "base/timer/timer.h" 76 #include "base/timer/timer.h"
77 #include "chrome/browser/ui/process_singleton_dialog_linux.h"
78 #include "chrome/common/chrome_constants.h" 77 #include "chrome/common/chrome_constants.h"
79 #include "content/public/browser/browser_thread.h" 78 #include "content/public/browser/browser_thread.h"
80 #include "grit/chromium_strings.h" 79 #include "grit/chromium_strings.h"
81 #include "grit/generated_resources.h" 80 #include "grit/generated_resources.h"
82 #include "net/base/net_util.h" 81 #include "net/base/net_util.h"
83 #include "ui/base/l10n/l10n_util.h" 82 #include "ui/base/l10n/l10n_util.h"
84 83
84 #if defined(OS_LINUX)
85 #include "chrome/browser/ui/process_singleton_dialog_linux.h"
86 #endif
87
85 #if defined(TOOLKIT_VIEWS) && !defined(OS_CHROMEOS) 88 #if defined(TOOLKIT_VIEWS) && !defined(OS_CHROMEOS)
86 #include "ui/views/linux_ui/linux_ui.h" 89 #include "ui/views/linux_ui/linux_ui.h"
87 #endif 90 #endif
88 91
89 using content::BrowserThread; 92 using content::BrowserThread;
90 93
91 const int ProcessSingleton::kTimeoutInSeconds; 94 const int ProcessSingleton::kTimeoutInSeconds;
92 95
93 namespace { 96 namespace {
94 97
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 *pid = -1; 294 *pid = -1;
292 295
293 return true; 296 return true;
294 } 297 }
295 298
296 // Returns true if the user opted to unlock the profile. 299 // Returns true if the user opted to unlock the profile.
297 bool DisplayProfileInUseError(const base::FilePath& lock_path, 300 bool DisplayProfileInUseError(const base::FilePath& lock_path,
298 const std::string& hostname, 301 const std::string& hostname,
299 int pid) { 302 int pid) {
300 base::string16 error = l10n_util::GetStringFUTF16( 303 base::string16 error = l10n_util::GetStringFUTF16(
301 IDS_PROFILE_IN_USE_LINUX, 304 IDS_PROFILE_IN_USE_POSIX,
302 base::IntToString16(pid), 305 base::IntToString16(pid),
303 base::ASCIIToUTF16(hostname)); 306 base::ASCIIToUTF16(hostname));
307 LOG(ERROR) << base::SysWideToNativeMB(base::UTF16ToWide(error)).c_str();
308
309 if (g_disable_prompt)
310 return false;
311
312 #if defined(OS_LINUX)
304 base::string16 relaunch_button_text = l10n_util::GetStringUTF16( 313 base::string16 relaunch_button_text = l10n_util::GetStringUTF16(
305 IDS_PROFILE_IN_USE_LINUX_RELAUNCH); 314 IDS_PROFILE_IN_USE_LINUX_RELAUNCH);
306 LOG(ERROR) << base::SysWideToNativeMB(base::UTF16ToWide(error)).c_str(); 315 return ShowProcessSingletonDialog(error, relaunch_button_text);
307 if (!g_disable_prompt) 316 #elif defined(OS_MACOSX)
308 return ShowProcessSingletonDialog(error, relaunch_button_text); 317 // On Mac, always usurp the lock.
318 return true;
319 #endif
320
321 NOTREACHED();
309 return false; 322 return false;
310 } 323 }
311 324
312 bool IsChromeProcess(pid_t pid) { 325 bool IsChromeProcess(pid_t pid) {
313 base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid)); 326 base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid));
314 return (!other_chrome_path.empty() && 327 return (!other_chrome_path.empty() &&
315 other_chrome_path.BaseName() == 328 other_chrome_path.BaseName() ==
316 base::FilePath(chrome::kBrowserProcessExecutableName)); 329 base::FilePath(chrome::kBrowserProcessExecutableName));
317 } 330 }
318 331
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 sizeof(addr))); 399 sizeof(addr)));
387 return (ret == 0); 400 return (ret == 0);
388 } else { 401 } else {
389 // File is missing, or other error. 402 // File is missing, or other error.
390 if (errno != ENOENT) 403 if (errno != ENOENT)
391 PLOG(ERROR) << "readlink failed"; 404 PLOG(ERROR) << "readlink failed";
392 return false; 405 return false;
393 } 406 }
394 } 407 }
395 408
409 #if defined(OS_MACOSX)
410 bool ReplaceOldSingletonLock(const base::FilePath& symlink_content,
411 const base::FilePath& lock_path) {
412 // Try taking an flock(2) on the file. Failure means the lock is taken so we
413 // should quit.
414 int lock_fd = HANDLE_EINTR(open(lock_path.value().c_str(),
415 O_RDWR | O_CREAT | O_SYMLINK, 0644));
Scott Hess - ex-Googler 2014/04/24 21:54:43 This indentation is wrong, the O_RDWR is w/in the
jackhou1 2014/04/28 05:20:16 Done.
416 if (lock_fd == -1) {
417 PLOG(ERROR) << "Could not open singleton lock";
418 return false;
419 }
420
421 int rc = HANDLE_EINTR(flock(lock_fd, LOCK_EX|LOCK_NB));
422 if (rc == -1) {
423 if (errno == EWOULDBLOCK) {
424 LOG(ERROR) << "Singleton lock held by old process.";
425 } else {
426 PLOG(ERROR) << "Error locking singleton lock";
427 }
Scott Hess - ex-Googler 2014/04/24 21:54:43 Close lock_fd, or use a ScopedFD on it. Actually,
jackhou1 2014/04/28 05:20:16 Done.
428 return false;
429 }
430
431 // Successfully taking the lock means we can replace it with the a new symlink
432 // lock. We never flock() the lock file from now on. I.e. we assume that an
433 // old version of Chrome will not run with the same user data dir after this
434 // version has run.
Scott Hess - ex-Googler 2014/04/24 21:54:43 What happens if this case occurs? Is the user's b
jackhou1 2014/04/28 05:20:16 The older version of Chrome will replace the symli
435 base::ScopedTempDir temp_lock_dir;
436 if (!temp_lock_dir.CreateUniqueTempDirUnderPath(lock_path.DirName())) {
Scott Hess - ex-Googler 2014/04/24 21:54:43 My guess is that this code will never crash. BUT,
jackhou1 2014/04/28 05:20:16 Putting it in the same directory ensures it's on t
Scott Hess - ex-Googler 2014/04/28 17:41:39 Sounds good.
437 LOG(ERROR) << "Could not create temp_lock_dir";
438 return false;
439 }
440 base::FilePath temp_lock_path =
441 temp_lock_dir.path().Append(chrome::kSingletonLockFilename);
442 if (!SymlinkPath(symlink_content, temp_lock_path)) {
443 LOG(ERROR) << "Could not create temp symlink.";
444 return false;
445 }
446
447 rc = rename(temp_lock_path.value().c_str(), lock_path.value().c_str());
mattm 2014/04/24 22:58:51 Is all of this even necessary? The rest of the cod
Scott Hess - ex-Googler 2014/04/25 15:26:54 It's atomically locking against the previous brows
jackhou1 2014/04/28 05:20:16 Changed to just deleting the old SingletonLock.
448 if (rc == -1) {
449 PLOG(ERROR) << "Could not replace singleton lock with symlink";
450 return false;
451 }
452
453 return true;
454 }
455 #endif // defined(OS_MACOSX)
456
396 } // namespace 457 } // namespace
397 458
398 /////////////////////////////////////////////////////////////////////////////// 459 ///////////////////////////////////////////////////////////////////////////////
399 // ProcessSingleton::LinuxWatcher 460 // ProcessSingleton::LinuxWatcher
400 // A helper class for a Linux specific implementation of the process singleton. 461 // A helper class for a Linux specific implementation of the process singleton.
401 // This class sets up a listener on the singleton socket and handles parsing 462 // This class sets up a listener on the singleton socket and handles parsing
402 // messages that come in on the singleton socket. 463 // messages that come in on the singleton socket.
403 class ProcessSingleton::LinuxWatcher 464 class ProcessSingleton::LinuxWatcher
404 : public base::MessageLoopForIO::Watcher, 465 : public base::MessageLoopForIO::Watcher,
405 public base::MessageLoop::DestructionObserver, 466 public base::MessageLoop::DestructionObserver,
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after
876 // processes can find it out. 937 // processes can find it out.
877 base::FilePath symlink_content(base::StringPrintf( 938 base::FilePath symlink_content(base::StringPrintf(
878 "%s%c%u", 939 "%s%c%u",
879 net::GetHostName().c_str(), 940 net::GetHostName().c_str(),
880 kLockDelimiter, 941 kLockDelimiter,
881 current_pid_)); 942 current_pid_));
882 943
883 // Create symbol link before binding the socket, to ensure only one instance 944 // Create symbol link before binding the socket, to ensure only one instance
884 // can have the socket open. 945 // can have the socket open.
885 if (!SymlinkPath(symlink_content, lock_path_)) { 946 if (!SymlinkPath(symlink_content, lock_path_)) {
886 // If we failed to create the lock, most likely another instance won the 947 // TODO(jackhou): Remove this case once this code is stable on Mac.
Scott Hess - ex-Googler 2014/04/24 21:54:43 Log a tracking bug for this, and reference it here
jackhou1 2014/04/28 05:20:16 Done. http://crbug.com/367612 Yeah, it's probably
887 // startup race. 948 #if defined(OS_MACOSX)
888 return false; 949 // On Mac, the lock could be held by the old process singleton code.
950 if (errno == EEXIST && !base::IsLink(lock_path_))
951 return ReplaceOldSingletonLock(symlink_content, lock_path_);
mattm 2014/04/24 22:58:51 Unconditionally returning here doesn't seem right.
jackhou1 2014/04/28 05:20:16 Fixed. Also updated test.
952 #endif
953 // If we failed to create the lock, most likely another instance won the
954 // startup race.
955 return false;
889 } 956 }
890 957
891 // Create the socket file somewhere in /tmp which is usually mounted as a 958 // Create the socket file somewhere in /tmp which is usually mounted as a
892 // normal filesystem. Some network filesystems (notably AFS) are screwy and 959 // normal filesystem. Some network filesystems (notably AFS) are screwy and
893 // do not support Unix domain sockets. 960 // do not support Unix domain sockets.
894 if (!socket_dir_.CreateUniqueTempDir()) { 961 if (!socket_dir_.CreateUniqueTempDir()) {
895 LOG(ERROR) << "Failed to create socket directory."; 962 LOG(ERROR) << "Failed to create socket directory.";
896 return false; 963 return false;
897 } 964 }
965
966 // Check that the directory was created with the correct permissions.
967 int dir_mode = 0;
968 CHECK(base::GetPosixFilePermissions(socket_dir_.path(), &dir_mode) &&
969 dir_mode == base::FILE_PERMISSION_USER_MASK)
970 << "Temp directory mode is not 700: " << std::oct << dir_mode;
971
898 // Setup the socket symlink and the two cookies. 972 // Setup the socket symlink and the two cookies.
899 base::FilePath socket_target_path = 973 base::FilePath socket_target_path =
900 socket_dir_.path().Append(chrome::kSingletonSocketFilename); 974 socket_dir_.path().Append(chrome::kSingletonSocketFilename);
901 base::FilePath cookie(GenerateCookie()); 975 base::FilePath cookie(GenerateCookie());
902 base::FilePath remote_cookie_path = 976 base::FilePath remote_cookie_path =
903 socket_dir_.path().Append(chrome::kSingletonCookieFilename); 977 socket_dir_.path().Append(chrome::kSingletonCookieFilename);
904 UnlinkPath(socket_path_); 978 UnlinkPath(socket_path_);
905 UnlinkPath(cookie_path_); 979 UnlinkPath(cookie_path_);
906 if (!SymlinkPath(socket_target_path, socket_path_) || 980 if (!SymlinkPath(socket_target_path, socket_path_) ||
907 !SymlinkPath(cookie, cookie_path_) || 981 !SymlinkPath(cookie, cookie_path_) ||
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
977 } 1051 }
978 1052
979 void ProcessSingleton::KillProcess(int pid) { 1053 void ProcessSingleton::KillProcess(int pid) {
980 // TODO(james.su@gmail.com): Is SIGKILL ok? 1054 // TODO(james.su@gmail.com): Is SIGKILL ok?
981 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); 1055 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
982 // ESRCH = No Such Process (can happen if the other process is already in 1056 // ESRCH = No Such Process (can happen if the other process is already in
983 // progress of shutting down and finishes before we try to kill it). 1057 // progress of shutting down and finishes before we try to kill it).
984 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 1058 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
985 << safe_strerror(errno); 1059 << safe_strerror(errno);
986 } 1060 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698