Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 769 std::string hostname; | 769 std::string hostname; |
| 770 int pid; | 770 int pid; |
| 771 if (!ParseLockPath(lock_path_, &hostname, &pid)) { | 771 if (!ParseLockPath(lock_path_, &hostname, &pid)) { |
| 772 // No lockfile exists. | 772 // No lockfile exists. |
| 773 return PROCESS_NONE; | 773 return PROCESS_NONE; |
| 774 } | 774 } |
| 775 | 775 |
| 776 if (hostname.empty()) { | 776 if (hostname.empty()) { |
| 777 // Invalid lockfile. | 777 // Invalid lockfile. |
| 778 UnlinkPath(lock_path_); | 778 UnlinkPath(lock_path_); |
| 779 UMA_HISTOGRAM_ENUMERATION( | |
| 780 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 781 INVALID_LOCK_FILE, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
|
gab
2017/05/10 15:16:50
Each UMA macro expands to a fair amount of code. E
Alexey Seren
2017/05/11 13:42:05
Acknowledged.
| |
| 779 return PROCESS_NONE; | 782 return PROCESS_NONE; |
| 780 } | 783 } |
| 781 | 784 |
| 782 if (hostname != net::GetHostName() && !IsChromeProcess(pid)) { | 785 if (hostname != net::GetHostName() && !IsChromeProcess(pid)) { |
| 783 // Locked by process on another host. If the user selected to unlock | 786 // Locked by process on another host. If the user selected to unlock |
| 784 // the profile, try to continue; otherwise quit. | 787 // the profile, try to continue; otherwise quit. |
| 785 if (DisplayProfileInUseError(lock_path_, hostname, pid)) { | 788 if (DisplayProfileInUseError(lock_path_, hostname, pid)) { |
| 786 UnlinkPath(lock_path_); | 789 UnlinkPath(lock_path_); |
| 790 UMA_HISTOGRAM_ENUMERATION( | |
| 791 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 792 PROFILE_UNLOCKED, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 787 return PROCESS_NONE; | 793 return PROCESS_NONE; |
| 788 } | 794 } |
| 789 return PROFILE_IN_USE; | 795 return PROFILE_IN_USE; |
| 790 } | 796 } |
| 791 | 797 |
| 792 if (!IsChromeProcess(pid)) { | 798 if (!IsChromeProcess(pid)) { |
| 793 // Orphaned lockfile (no process with pid, or non-chrome process.) | 799 // Orphaned lockfile (no process with pid, or non-chrome process.) |
| 800 UMA_HISTOGRAM_ENUMERATION( | |
| 801 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 802 ORPHANED_LOCK_FILE, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
|
gab
2017/05/10 15:16:50
To be consistent I'd say have the UMA logging alwa
Alexey Seren
2017/05/11 13:42:05
Acknowledged.
| |
| 794 UnlinkPath(lock_path_); | 803 UnlinkPath(lock_path_); |
| 795 return PROCESS_NONE; | 804 return PROCESS_NONE; |
| 796 } | 805 } |
| 797 | 806 |
| 798 if (IsSameChromeInstance(pid)) { | 807 if (IsSameChromeInstance(pid)) { |
| 799 // Orphaned lockfile (pid is part of same chrome instance we are, even | 808 // Orphaned lockfile (pid is part of same chrome instance we are, even |
| 800 // though we haven't tried to create a lockfile yet). | 809 // though we haven't tried to create a lockfile yet). |
| 801 UnlinkPath(lock_path_); | 810 UnlinkPath(lock_path_); |
| 811 UMA_HISTOGRAM_ENUMERATION( | |
| 812 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 813 SAME_BROWSER_INSTANCE, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 802 return PROCESS_NONE; | 814 return PROCESS_NONE; |
| 803 } | 815 } |
| 804 | 816 |
| 805 if (retries == retry_attempts) { | 817 if (retries == retry_attempts) { |
| 818 if (kill_unresponsive) { | |
| 819 UMA_HISTOGRAM_ENUMERATION( | |
| 820 "Chrome.ProcessSingleton.RemoteHungProcessTerminateReason", | |
| 821 NOTIFY_ATTEMPTS_EXCEEDED, MAX_REMOTE_HUNG_PROCESS_TERMINATE_REASON); | |
|
gab
2017/05/10 15:16:50
Same here, instead of if (kill_unresponsive) {}, m
Alexey Seren
2017/05/11 13:42:05
Acknowledged.
| |
| 822 } | |
| 806 // Retries failed. Kill the unresponsive chrome process and continue. | 823 // Retries failed. Kill the unresponsive chrome process and continue. |
| 807 if (!kill_unresponsive || !KillProcessByLockPath()) | 824 if (!kill_unresponsive || !KillProcessByLockPath()) |
| 808 return PROFILE_IN_USE; | 825 return PROFILE_IN_USE; |
| 809 return PROCESS_NONE; | 826 return PROCESS_NONE; |
| 810 } | 827 } |
| 811 | 828 |
| 812 base::PlatformThread::Sleep(sleep_interval); | 829 base::PlatformThread::Sleep(sleep_interval); |
| 813 } | 830 } |
| 814 | 831 |
| 815 timeval socket_timeout = TimeDeltaToTimeVal(timeout); | 832 timeval socket_timeout = TimeDeltaToTimeVal(timeout); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 831 | 848 |
| 832 const std::vector<std::string>& argv = cmd_line.argv(); | 849 const std::vector<std::string>& argv = cmd_line.argv(); |
| 833 for (std::vector<std::string>::const_iterator it = argv.begin(); | 850 for (std::vector<std::string>::const_iterator it = argv.begin(); |
| 834 it != argv.end(); ++it) { | 851 it != argv.end(); ++it) { |
| 835 to_send.push_back(kTokenDelimiter); | 852 to_send.push_back(kTokenDelimiter); |
| 836 to_send.append(*it); | 853 to_send.append(*it); |
| 837 } | 854 } |
| 838 | 855 |
| 839 // Send the message | 856 // Send the message |
| 840 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { | 857 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { |
| 858 if (kill_unresponsive) { | |
| 859 UMA_HISTOGRAM_ENUMERATION( | |
| 860 "Chrome.ProcessSingleton.RemoteHungProcessTerminateReason", | |
| 861 SOCKET_WRITE_FAILED, MAX_REMOTE_HUNG_PROCESS_TERMINATE_REASON); | |
| 862 } | |
| 841 // Try to kill the other process, because it might have been dead. | 863 // Try to kill the other process, because it might have been dead. |
| 842 if (!kill_unresponsive || !KillProcessByLockPath()) | 864 if (!kill_unresponsive || !KillProcessByLockPath()) |
| 843 return PROFILE_IN_USE; | 865 return PROFILE_IN_USE; |
| 844 return PROCESS_NONE; | 866 return PROCESS_NONE; |
| 845 } | 867 } |
| 846 | 868 |
| 847 if (shutdown(socket.fd(), SHUT_WR) < 0) | 869 if (shutdown(socket.fd(), SHUT_WR) < 0) |
| 848 PLOG(ERROR) << "shutdown() failed"; | 870 PLOG(ERROR) << "shutdown() failed"; |
| 849 | 871 |
| 850 // Read ACK message from the other process. It might be blocked for a certain | 872 // Read ACK message from the other process. It might be blocked for a certain |
| 851 // timeout, to make sure the other process has enough time to return ACK. | 873 // timeout, to make sure the other process has enough time to return ACK. |
| 852 char buf[kMaxACKMessageLength + 1]; | 874 char buf[kMaxACKMessageLength + 1]; |
| 853 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout); | 875 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout); |
| 854 | 876 |
| 855 // Failed to read ACK, the other process might have been frozen. | 877 // Failed to read ACK, the other process might have been frozen. |
| 856 if (len <= 0) { | 878 if (len <= 0) { |
| 879 if (kill_unresponsive) { | |
| 880 UMA_HISTOGRAM_ENUMERATION( | |
| 881 "Chrome.ProcessSingleton.RemoteHungProcessTerminateReason", | |
| 882 SOCKET_READ_FAILED, MAX_REMOTE_HUNG_PROCESS_TERMINATE_REASON); | |
| 883 } | |
| 857 if (!kill_unresponsive || !KillProcessByLockPath()) | 884 if (!kill_unresponsive || !KillProcessByLockPath()) |
| 858 return PROFILE_IN_USE; | 885 return PROFILE_IN_USE; |
| 859 return PROCESS_NONE; | 886 return PROCESS_NONE; |
| 860 } | 887 } |
| 861 | 888 |
| 862 buf[len] = '\0'; | 889 buf[len] = '\0'; |
| 863 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { | 890 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { |
| 864 // 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. |
| 892 UMA_HISTOGRAM_ENUMERATION( | |
| 893 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 894 REMOTE_PROCESS_SHUTTING_DOWN, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 865 return PROCESS_NONE; | 895 return PROCESS_NONE; |
| 866 } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) { | 896 } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) { |
| 867 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) | 897 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 868 // Likely NULL in unit tests. | 898 // Likely NULL in unit tests. |
| 869 views::LinuxUI* linux_ui = views::LinuxUI::instance(); | 899 views::LinuxUI* linux_ui = views::LinuxUI::instance(); |
| 870 if (linux_ui) | 900 if (linux_ui) |
| 871 linux_ui->NotifyWindowManagerStartupComplete(); | 901 linux_ui->NotifyWindowManagerStartupComplete(); |
| 872 #endif | 902 #endif |
| 873 | 903 |
| 874 // Assume the other process is handling the request. | 904 // Assume the other process is handling the request. |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1050 } | 1080 } |
| 1051 return true; | 1081 return true; |
| 1052 } | 1082 } |
| 1053 | 1083 |
| 1054 bool ProcessSingleton::KillProcessByLockPath() { | 1084 bool ProcessSingleton::KillProcessByLockPath() { |
| 1055 std::string hostname; | 1085 std::string hostname; |
| 1056 int pid; | 1086 int pid; |
| 1057 ParseLockPath(lock_path_, &hostname, &pid); | 1087 ParseLockPath(lock_path_, &hostname, &pid); |
| 1058 | 1088 |
| 1059 if (!hostname.empty() && hostname != net::GetHostName()) { | 1089 if (!hostname.empty() && hostname != net::GetHostName()) { |
| 1060 return DisplayProfileInUseError(lock_path_, hostname, pid); | 1090 bool res = DisplayProfileInUseError(lock_path_, hostname, pid); |
| 1091 if (res) { | |
| 1092 UnlinkPath(lock_path_); | |
|
Alexey Seren
2017/05/10 04:27:07
We need to unlink lock file if user selects to unl
gab
2017/05/10 15:16:50
Is this a bug fix? If so, should go in a separate
Alexey Seren
2017/05/11 13:42:05
Yes it is a bug fix. I will move it to separate CL
| |
| 1093 UMA_HISTOGRAM_ENUMERATION( | |
| 1094 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 1095 PROFILE_UNLOCKED, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 1096 } | |
| 1097 return res; | |
| 1061 } | 1098 } |
| 1062 UnlinkPath(lock_path_); | 1099 UnlinkPath(lock_path_); |
| 1063 | 1100 |
| 1064 if (IsSameChromeInstance(pid)) | 1101 if (IsSameChromeInstance(pid)) { |
| 1102 UMA_HISTOGRAM_ENUMERATION( | |
| 1103 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 1104 SAME_BROWSER_INSTANCE, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 1065 return true; | 1105 return true; |
| 1106 } | |
| 1066 | 1107 |
| 1067 if (pid > 0) { | 1108 if (pid > 0) { |
| 1068 kill_callback_.Run(pid); | 1109 kill_callback_.Run(pid); |
| 1069 return true; | 1110 return true; |
| 1070 } | 1111 } |
| 1071 | 1112 |
| 1113 UMA_HISTOGRAM_ENUMERATION( | |
| 1114 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", | |
| 1115 FAILED_TO_EXTRACT_PID, MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 1116 | |
| 1072 LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value(); | 1117 LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value(); |
| 1073 return true; | 1118 return true; |
| 1074 } | 1119 } |
| 1075 | 1120 |
| 1076 void ProcessSingleton::KillProcess(int pid) { | 1121 void ProcessSingleton::KillProcess(int pid) { |
| 1077 // TODO(james.su@gmail.com): Is SIGKILL ok? | 1122 // TODO(james.su@gmail.com): Is SIGKILL ok? |
| 1078 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); | 1123 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); |
| 1079 // ESRCH = No Such Process (can happen if the other process is already in | 1124 // ESRCH = No Such Process (can happen if the other process is already in |
| 1080 // progress of shutting down and finishes before we try to kill it). | 1125 // progress of shutting down and finishes before we try to kill it). |
| 1081 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " | 1126 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " |
| 1082 << base::safe_strerror(errno); | 1127 << base::safe_strerror(errno); |
| 1128 | |
| 1129 int error_code = (rv == 0) ? 0 : errno; | |
| 1130 UMA_HISTOGRAM_SPARSE_SLOWLY( | |
| 1131 "Chrome.ProcessSingleton.TerminateProcessErrorCode.Posix", error_code); | |
| 1132 | |
| 1133 RemoteProcessInteractionResult action = TERMINATE_SUCCEEDED; | |
| 1134 if (rv != 0) { | |
| 1135 switch (error_code) { | |
| 1136 case ESRCH: | |
| 1137 action = REMOTE_PROCESS_NOT_FOUND; | |
| 1138 break; | |
| 1139 case EPERM: | |
| 1140 action = TERMINATE_NOT_ENOUGH_PERMISSIONS; | |
| 1141 break; | |
| 1142 default: { action = TERMINATE_FAILED; } | |
|
gab
2017/05/10 15:16:50
use same syntax as other cases for default, i.e.
Alexey Seren
2017/05/11 13:42:05
Acknowledged.
| |
| 1143 } | |
| 1144 } | |
| 1145 UMA_HISTOGRAM_ENUMERATION( | |
| 1146 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", action, | |
| 1147 MAX_HUNG_REMOTE_PROCESS_ACTION); | |
| 1083 } | 1148 } |
| OLD | NEW |