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

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

Issue 2880333004: Fix not deleting a lockfile or not killing a frozen browser on hostname change (Closed)
Patch Set: Renamed KillProcessByLockPath() parameter to is_connected_to_socket Created 3 years, 6 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
« no previous file with comments | « chrome/browser/process_singleton.h ('k') | chrome/browser/process_singleton_posix_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 const char kACKToken[] = "ACK"; 115 const char kACKToken[] = "ACK";
116 const char kShutdownToken[] = "SHUTDOWN"; 116 const char kShutdownToken[] = "SHUTDOWN";
117 const char kTokenDelimiter = '\0'; 117 const char kTokenDelimiter = '\0';
118 const int kMaxMessageLength = 32 * 1024; 118 const int kMaxMessageLength = 32 * 1024;
119 const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1; 119 const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
120 120
121 const char kLockDelimiter = '-'; 121 const char kLockDelimiter = '-';
122 122
123 bool g_disable_prompt = false; 123 bool g_disable_prompt = false;
124 bool g_skip_is_chrome_process_check = false; 124 bool g_skip_is_chrome_process_check = false;
125 bool g_user_opted_unlock_in_use_profile = false;
125 126
126 // Set the close-on-exec bit on a file descriptor. 127 // Set the close-on-exec bit on a file descriptor.
127 // Returns 0 on success, -1 on failure. 128 // Returns 0 on success, -1 on failure.
128 int SetCloseOnExec(int fd) { 129 int SetCloseOnExec(int fd) {
129 int flags = fcntl(fd, F_GETFD, 0); 130 int flags = fcntl(fd, F_GETFD, 0);
130 if (-1 == flags) 131 if (-1 == flags)
131 return flags; 132 return flags;
132 if (flags & FD_CLOEXEC) 133 if (flags & FD_CLOEXEC)
133 return 0; 134 return 0;
134 return fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 135 return fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 bool DisplayProfileInUseError(const base::FilePath& lock_path, 316 bool DisplayProfileInUseError(const base::FilePath& lock_path,
316 const std::string& hostname, 317 const std::string& hostname,
317 int pid) { 318 int pid) {
318 base::string16 error = l10n_util::GetStringFUTF16( 319 base::string16 error = l10n_util::GetStringFUTF16(
319 IDS_PROFILE_IN_USE_POSIX, 320 IDS_PROFILE_IN_USE_POSIX,
320 base::IntToString16(pid), 321 base::IntToString16(pid),
321 base::ASCIIToUTF16(hostname)); 322 base::ASCIIToUTF16(hostname));
322 LOG(ERROR) << error; 323 LOG(ERROR) << error;
323 324
324 if (g_disable_prompt) 325 if (g_disable_prompt)
325 return false; 326 return g_user_opted_unlock_in_use_profile;
326 327
327 #if defined(OS_LINUX) 328 #if defined(OS_LINUX)
328 base::string16 relaunch_button_text = l10n_util::GetStringUTF16( 329 base::string16 relaunch_button_text = l10n_util::GetStringUTF16(
329 IDS_PROFILE_IN_USE_LINUX_RELAUNCH); 330 IDS_PROFILE_IN_USE_LINUX_RELAUNCH);
330 return ShowProcessSingletonDialog(error, relaunch_button_text); 331 return ShowProcessSingletonDialog(error, relaunch_button_text);
331 #elif defined(OS_MACOSX) 332 #elif defined(OS_MACOSX)
332 // On Mac, always usurp the lock. 333 // On Mac, always usurp the lock.
333 return true; 334 return true;
334 #endif 335 #endif
335 336
336 NOTREACHED(); 337 NOTREACHED();
337 return false; 338 return false;
338 } 339 }
339 340
340 bool IsChromeProcess(pid_t pid) { 341 bool IsChromeProcess(pid_t pid) {
342 if (g_skip_is_chrome_process_check)
343 return true;
344
341 base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid)); 345 base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid));
342 return (!other_chrome_path.empty() && 346 return (!other_chrome_path.empty() &&
343 (g_skip_is_chrome_process_check || 347 other_chrome_path.BaseName() ==
344 other_chrome_path.BaseName() == 348 base::FilePath(chrome::kBrowserProcessExecutableName));
345 base::FilePath(chrome::kBrowserProcessExecutableName)));
346 } 349 }
347 350
348 // A helper class to hold onto a socket. 351 // A helper class to hold onto a socket.
349 class ScopedSocket { 352 class ScopedSocket {
350 public: 353 public:
351 ScopedSocket() : fd_(-1) { Reset(); } 354 ScopedSocket() : fd_(-1) { Reset(); }
352 ~ScopedSocket() { Close(); } 355 ~ScopedSocket() { Close(); }
353 int fd() { return fd_; } 356 int fd() { return fd_; }
354 void Reset() { 357 void Reset() {
355 Close(); 358 Close();
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
818 if (IsSameChromeInstance(pid)) { 821 if (IsSameChromeInstance(pid)) {
819 // Orphaned lockfile (pid is part of same chrome instance we are, even 822 // Orphaned lockfile (pid is part of same chrome instance we are, even
820 // though we haven't tried to create a lockfile yet). 823 // though we haven't tried to create a lockfile yet).
821 UnlinkPath(lock_path_); 824 UnlinkPath(lock_path_);
822 SendRemoteProcessInteractionResultHistogram(SAME_BROWSER_INSTANCE); 825 SendRemoteProcessInteractionResultHistogram(SAME_BROWSER_INSTANCE);
823 return PROCESS_NONE; 826 return PROCESS_NONE;
824 } 827 }
825 828
826 if (retries == retry_attempts) { 829 if (retries == retry_attempts) {
827 // Retries failed. Kill the unresponsive chrome process and continue. 830 // Retries failed. Kill the unresponsive chrome process and continue.
828 if (!kill_unresponsive || !KillProcessByLockPath()) 831 if (!kill_unresponsive || !KillProcessByLockPath(false))
829 return PROFILE_IN_USE; 832 return PROFILE_IN_USE;
830 SendRemoteHungProcessTerminateReasonHistogram(NOTIFY_ATTEMPTS_EXCEEDED); 833 SendRemoteHungProcessTerminateReasonHistogram(NOTIFY_ATTEMPTS_EXCEEDED);
831 return PROCESS_NONE; 834 return PROCESS_NONE;
832 } 835 }
833 836
834 base::PlatformThread::Sleep(sleep_interval); 837 base::PlatformThread::Sleep(sleep_interval);
835 } 838 }
836 839
837 timeval socket_timeout = TimeDeltaToTimeVal(timeout); 840 timeval socket_timeout = TimeDeltaToTimeVal(timeout);
838 setsockopt(socket.fd(), 841 setsockopt(socket.fd(),
(...skipping 15 matching lines...) Expand all
854 const std::vector<std::string>& argv = cmd_line.argv(); 857 const std::vector<std::string>& argv = cmd_line.argv();
855 for (std::vector<std::string>::const_iterator it = argv.begin(); 858 for (std::vector<std::string>::const_iterator it = argv.begin();
856 it != argv.end(); ++it) { 859 it != argv.end(); ++it) {
857 to_send.push_back(kTokenDelimiter); 860 to_send.push_back(kTokenDelimiter);
858 to_send.append(*it); 861 to_send.append(*it);
859 } 862 }
860 863
861 // Send the message 864 // Send the message
862 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { 865 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) {
863 // Try to kill the other process, because it might have been dead. 866 // Try to kill the other process, because it might have been dead.
864 if (!kill_unresponsive || !KillProcessByLockPath()) 867 if (!kill_unresponsive || !KillProcessByLockPath(true))
865 return PROFILE_IN_USE; 868 return PROFILE_IN_USE;
866 SendRemoteHungProcessTerminateReasonHistogram(SOCKET_WRITE_FAILED); 869 SendRemoteHungProcessTerminateReasonHistogram(SOCKET_WRITE_FAILED);
867 return PROCESS_NONE; 870 return PROCESS_NONE;
868 } 871 }
869 872
870 if (shutdown(socket.fd(), SHUT_WR) < 0) 873 if (shutdown(socket.fd(), SHUT_WR) < 0)
871 PLOG(ERROR) << "shutdown() failed"; 874 PLOG(ERROR) << "shutdown() failed";
872 875
873 // Read ACK message from the other process. It might be blocked for a certain 876 // Read ACK message from the other process. It might be blocked for a certain
874 // timeout, to make sure the other process has enough time to return ACK. 877 // timeout, to make sure the other process has enough time to return ACK.
875 char buf[kMaxACKMessageLength + 1]; 878 char buf[kMaxACKMessageLength + 1];
876 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout); 879 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout);
877 880
878 // Failed to read ACK, the other process might have been frozen. 881 // Failed to read ACK, the other process might have been frozen.
879 if (len <= 0) { 882 if (len <= 0) {
880 if (!kill_unresponsive || !KillProcessByLockPath()) 883 if (!kill_unresponsive || !KillProcessByLockPath(true))
881 return PROFILE_IN_USE; 884 return PROFILE_IN_USE;
882 SendRemoteHungProcessTerminateReasonHistogram(SOCKET_READ_FAILED); 885 SendRemoteHungProcessTerminateReasonHistogram(SOCKET_READ_FAILED);
883 return PROCESS_NONE; 886 return PROCESS_NONE;
884 } 887 }
885 888
886 buf[len] = '\0'; 889 buf[len] = '\0';
887 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { 890 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
888 // The other process is shutting down, it's safe to start a new process. 891 // The other process is shutting down, it's safe to start a new process.
889 SendRemoteProcessInteractionResultHistogram(REMOTE_PROCESS_SHUTTING_DOWN); 892 SendRemoteProcessInteractionResultHistogram(REMOTE_PROCESS_SHUTTING_DOWN);
890 return PROCESS_NONE; 893 return PROCESS_NONE;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 962
960 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) { 963 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) {
961 current_pid_ = pid; 964 current_pid_ = pid;
962 } 965 }
963 966
964 void ProcessSingleton::OverrideKillCallbackForTesting( 967 void ProcessSingleton::OverrideKillCallbackForTesting(
965 const base::Callback<void(int)>& callback) { 968 const base::Callback<void(int)>& callback) {
966 kill_callback_ = callback; 969 kill_callback_ = callback;
967 } 970 }
968 971
972 // static
969 void ProcessSingleton::DisablePromptForTesting() { 973 void ProcessSingleton::DisablePromptForTesting() {
970 g_disable_prompt = true; 974 g_disable_prompt = true;
971 } 975 }
972 976
977 // static
973 void ProcessSingleton::SkipIsChromeProcessCheckForTesting(bool skip) { 978 void ProcessSingleton::SkipIsChromeProcessCheckForTesting(bool skip) {
974 g_skip_is_chrome_process_check = skip; 979 g_skip_is_chrome_process_check = skip;
975 } 980 }
976 981
982 // static
983 void ProcessSingleton::SetUserOptedUnlockInUseProfileForTesting(
984 bool set_unlock) {
985 g_user_opted_unlock_in_use_profile = set_unlock;
986 }
987
977 bool ProcessSingleton::Create() { 988 bool ProcessSingleton::Create() {
978 int sock; 989 int sock;
979 sockaddr_un addr; 990 sockaddr_un addr;
980 991
981 // The symlink lock is pointed to the hostname and process id, so other 992 // The symlink lock is pointed to the hostname and process id, so other
982 // processes can find it out. 993 // processes can find it out.
983 base::FilePath symlink_content(base::StringPrintf( 994 base::FilePath symlink_content(base::StringPrintf(
984 "%s%c%u", 995 "%s%c%u",
985 net::GetHostName().c_str(), 996 net::GetHostName().c_str(),
986 kLockDelimiter, 997 kLockDelimiter,
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
1073 while (pid != cur_pid) { 1084 while (pid != cur_pid) {
1074 pid = base::GetParentProcessId(pid); 1085 pid = base::GetParentProcessId(pid);
1075 if (pid < 0) 1086 if (pid < 0)
1076 return false; 1087 return false;
1077 if (!IsChromeProcess(pid)) 1088 if (!IsChromeProcess(pid))
1078 return false; 1089 return false;
1079 } 1090 }
1080 return true; 1091 return true;
1081 } 1092 }
1082 1093
1083 bool ProcessSingleton::KillProcessByLockPath() { 1094 bool ProcessSingleton::KillProcessByLockPath(bool is_connected_to_socket) {
1084 std::string hostname; 1095 std::string hostname;
1085 int pid; 1096 int pid;
1086 ParseLockPath(lock_path_, &hostname, &pid); 1097 ParseLockPath(lock_path_, &hostname, &pid);
1087 1098
1088 if (!hostname.empty() && hostname != net::GetHostName()) { 1099 if (!hostname.empty() && hostname != net::GetHostName() &&
1100 !is_connected_to_socket) {
1089 bool res = DisplayProfileInUseError(lock_path_, hostname, pid); 1101 bool res = DisplayProfileInUseError(lock_path_, hostname, pid);
1090 if (res) 1102 if (res) {
1103 UnlinkPath(lock_path_);
1091 SendRemoteProcessInteractionResultHistogram(PROFILE_UNLOCKED_BEFORE_KILL); 1104 SendRemoteProcessInteractionResultHistogram(PROFILE_UNLOCKED_BEFORE_KILL);
1105 }
1092 return res; 1106 return res;
1093 } 1107 }
1094 UnlinkPath(lock_path_); 1108 UnlinkPath(lock_path_);
1095 1109
1096 if (IsSameChromeInstance(pid)) { 1110 if (IsSameChromeInstance(pid)) {
1097 SendRemoteProcessInteractionResultHistogram( 1111 SendRemoteProcessInteractionResultHistogram(
1098 SAME_BROWSER_INSTANCE_BEFORE_KILL); 1112 SAME_BROWSER_INSTANCE_BEFORE_KILL);
1099 return true; 1113 return true;
1100 } 1114 }
1101 1115
(...skipping 29 matching lines...) Expand all
1131 case EPERM: 1145 case EPERM:
1132 action = TERMINATE_NOT_ENOUGH_PERMISSIONS; 1146 action = TERMINATE_NOT_ENOUGH_PERMISSIONS;
1133 break; 1147 break;
1134 default: 1148 default:
1135 action = TERMINATE_FAILED; 1149 action = TERMINATE_FAILED;
1136 break; 1150 break;
1137 } 1151 }
1138 } 1152 }
1139 SendRemoteProcessInteractionResultHistogram(action); 1153 SendRemoteProcessInteractionResultHistogram(action);
1140 } 1154 }
OLDNEW
« no previous file with comments | « chrome/browser/process_singleton.h ('k') | chrome/browser/process_singleton_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698