| Index: chrome/browser/process_singleton_posix.cc
|
| diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
|
| index f8786c67e6404c2678b65f8c0b16da815ce02d74..c684f51ce101f2d97c355b3006acc19f61ae13af 100644
|
| --- a/chrome/browser/process_singleton_posix.cc
|
| +++ b/chrome/browser/process_singleton_posix.cc
|
| @@ -111,7 +111,6 @@ const int kTimeoutInSeconds = 20;
|
| // Number of retries to notify the browser. 20 retries over 20 seconds = 1 try
|
| // per second.
|
| const int kRetryAttempts = 20;
|
| -static bool g_disable_prompt;
|
| const char kStartToken[] = "START";
|
| const char kACKToken[] = "ACK";
|
| const char kShutdownToken[] = "SHUTDOWN";
|
| @@ -121,6 +120,9 @@ const int kMaxACKMessageLength = arraysize(kShutdownToken) - 1;
|
|
|
| const char kLockDelimiter = '-';
|
|
|
| +bool g_disable_prompt = false;
|
| +bool g_skip_is_chrome_process_check = false;
|
| +
|
| // Set the close-on-exec bit on a file descriptor.
|
| // Returns 0 on success, -1 on failure.
|
| int SetCloseOnExec(int fd) {
|
| @@ -338,8 +340,9 @@ bool DisplayProfileInUseError(const base::FilePath& lock_path,
|
| bool IsChromeProcess(pid_t pid) {
|
| base::FilePath other_chrome_path(base::GetProcessExecutablePath(pid));
|
| return (!other_chrome_path.empty() &&
|
| - other_chrome_path.BaseName() ==
|
| - base::FilePath(chrome::kBrowserProcessExecutableName));
|
| + (g_skip_is_chrome_process_check ||
|
| + other_chrome_path.BaseName() ==
|
| + base::FilePath(chrome::kBrowserProcessExecutableName)));
|
| }
|
|
|
| // A helper class to hold onto a socket.
|
| @@ -464,6 +467,20 @@ bool ReplaceOldSingletonLock(const base::FilePath& symlink_content,
|
| }
|
| #endif // defined(OS_MACOSX)
|
|
|
| +void SendRemoteProcessInteractionResultHistogram(
|
| + ProcessSingleton::RemoteProcessInteractionResult result) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "Chrome.ProcessSingleton.RemoteProcessInteractionResult", result,
|
| + ProcessSingleton::REMOTE_PROCESS_INTERACTION_RESULT_COUNT);
|
| +}
|
| +
|
| +void SendRemoteHungProcessTerminateReasonHistogram(
|
| + ProcessSingleton::RemoteHungProcessTerminateReason reason) {
|
| + UMA_HISTOGRAM_ENUMERATION(
|
| + "Chrome.ProcessSingleton.RemoteHungProcessTerminateReason", reason,
|
| + ProcessSingleton::REMOTE_HUNG_PROCESS_TERMINATE_REASON_COUNT);
|
| +}
|
| +
|
| } // namespace
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| @@ -776,6 +793,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| if (hostname.empty()) {
|
| // Invalid lockfile.
|
| UnlinkPath(lock_path_);
|
| + SendRemoteProcessInteractionResultHistogram(INVALID_LOCK_FILE);
|
| return PROCESS_NONE;
|
| }
|
|
|
| @@ -784,6 +802,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| // the profile, try to continue; otherwise quit.
|
| if (DisplayProfileInUseError(lock_path_, hostname, pid)) {
|
| UnlinkPath(lock_path_);
|
| + SendRemoteProcessInteractionResultHistogram(PROFILE_UNLOCKED);
|
| return PROCESS_NONE;
|
| }
|
| return PROFILE_IN_USE;
|
| @@ -792,6 +811,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| if (!IsChromeProcess(pid)) {
|
| // Orphaned lockfile (no process with pid, or non-chrome process.)
|
| UnlinkPath(lock_path_);
|
| + SendRemoteProcessInteractionResultHistogram(ORPHANED_LOCK_FILE);
|
| return PROCESS_NONE;
|
| }
|
|
|
| @@ -799,6 +819,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| // Orphaned lockfile (pid is part of same chrome instance we are, even
|
| // though we haven't tried to create a lockfile yet).
|
| UnlinkPath(lock_path_);
|
| + SendRemoteProcessInteractionResultHistogram(SAME_BROWSER_INSTANCE);
|
| return PROCESS_NONE;
|
| }
|
|
|
| @@ -806,6 +827,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| // Retries failed. Kill the unresponsive chrome process and continue.
|
| if (!kill_unresponsive || !KillProcessByLockPath())
|
| return PROFILE_IN_USE;
|
| + SendRemoteHungProcessTerminateReasonHistogram(NOTIFY_ATTEMPTS_EXCEEDED);
|
| return PROCESS_NONE;
|
| }
|
|
|
| @@ -841,6 +863,7 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| // Try to kill the other process, because it might have been dead.
|
| if (!kill_unresponsive || !KillProcessByLockPath())
|
| return PROFILE_IN_USE;
|
| + SendRemoteHungProcessTerminateReasonHistogram(SOCKET_WRITE_FAILED);
|
| return PROCESS_NONE;
|
| }
|
|
|
| @@ -856,12 +879,14 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
| if (len <= 0) {
|
| if (!kill_unresponsive || !KillProcessByLockPath())
|
| return PROFILE_IN_USE;
|
| + SendRemoteHungProcessTerminateReasonHistogram(SOCKET_READ_FAILED);
|
| 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.
|
| + SendRemoteProcessInteractionResultHistogram(REMOTE_PROCESS_SHUTTING_DOWN);
|
| return PROCESS_NONE;
|
| } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) {
|
| #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
|
| @@ -945,6 +970,10 @@ void ProcessSingleton::DisablePromptForTesting() {
|
| g_disable_prompt = true;
|
| }
|
|
|
| +void ProcessSingleton::SkipIsChromeProcessCheckForTesting(bool skip) {
|
| + g_skip_is_chrome_process_check = skip;
|
| +}
|
| +
|
| bool ProcessSingleton::Create() {
|
| int sock;
|
| sockaddr_un addr;
|
| @@ -1057,18 +1086,26 @@ bool ProcessSingleton::KillProcessByLockPath() {
|
| ParseLockPath(lock_path_, &hostname, &pid);
|
|
|
| if (!hostname.empty() && hostname != net::GetHostName()) {
|
| - return DisplayProfileInUseError(lock_path_, hostname, pid);
|
| + bool res = DisplayProfileInUseError(lock_path_, hostname, pid);
|
| + if (res)
|
| + SendRemoteProcessInteractionResultHistogram(PROFILE_UNLOCKED_BEFORE_KILL);
|
| + return res;
|
| }
|
| UnlinkPath(lock_path_);
|
|
|
| - if (IsSameChromeInstance(pid))
|
| + if (IsSameChromeInstance(pid)) {
|
| + SendRemoteProcessInteractionResultHistogram(
|
| + SAME_BROWSER_INSTANCE_BEFORE_KILL);
|
| return true;
|
| + }
|
|
|
| if (pid > 0) {
|
| kill_callback_.Run(pid);
|
| return true;
|
| }
|
|
|
| + SendRemoteProcessInteractionResultHistogram(FAILED_TO_EXTRACT_PID);
|
| +
|
| LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value();
|
| return true;
|
| }
|
| @@ -1080,4 +1117,24 @@ void ProcessSingleton::KillProcess(int pid) {
|
| // progress of shutting down and finishes before we try to kill it).
|
| DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
|
| << base::safe_strerror(errno);
|
| +
|
| + int error_code = (rv == 0) ? 0 : errno;
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY(
|
| + "Chrome.ProcessSingleton.TerminateProcessErrorCode.Posix", error_code);
|
| +
|
| + RemoteProcessInteractionResult action = TERMINATE_SUCCEEDED;
|
| + if (rv != 0) {
|
| + switch (error_code) {
|
| + case ESRCH:
|
| + action = REMOTE_PROCESS_NOT_FOUND;
|
| + break;
|
| + case EPERM:
|
| + action = TERMINATE_NOT_ENOUGH_PERMISSIONS;
|
| + break;
|
| + default:
|
| + action = TERMINATE_FAILED;
|
| + break;
|
| + }
|
| + }
|
| + SendRemoteProcessInteractionResultHistogram(action);
|
| }
|
|
|