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

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

Issue 2871793003: Added histograms on process singleton create when remote process exists and we cannot notify it (Closed)
Patch Set: Split histogram enums by platforms Created 3 years, 7 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
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 446 matching lines...) Expand 10 before | Expand all | Expand 10 after
457 // version has run. 457 // version has run.
458 if (!base::DeleteFile(lock_path, false)) { 458 if (!base::DeleteFile(lock_path, false)) {
459 PLOG(ERROR) << "Could not delete old singleton lock."; 459 PLOG(ERROR) << "Could not delete old singleton lock.";
460 return false; 460 return false;
461 } 461 }
462 462
463 return SymlinkPath(symlink_content, lock_path); 463 return SymlinkPath(symlink_content, lock_path);
464 } 464 }
465 #endif // defined(OS_MACOSX) 465 #endif // defined(OS_MACOSX)
466 466
467 void SendRemoteProcessInteractionResultHistogram(
468 ProcessSingleton::RemoteProcessInteractionResult result) {
469 UMA_HISTOGRAM_ENUMERATION(
470 "Chrome.ProcessSingleton.RemoteProcessInteractionResult", result,
471 ProcessSingleton::REMOTE_PROCESS_INTERACTION_RESULT_COUNT);
472 }
473
474 void SendRemoteHungProcessTerminateReasonHistogram(
475 ProcessSingleton::RemoteHungProcessTerminateReason reason) {
476 UMA_HISTOGRAM_ENUMERATION(
477 "Chrome.ProcessSingleton.RemoteHungProcessTerminateReason", reason,
478 ProcessSingleton::REMOTE_HUNG_PROCESS_TERMINATE_REASON_COUNT);
479 }
480
467 } // namespace 481 } // namespace
468 482
469 /////////////////////////////////////////////////////////////////////////////// 483 ///////////////////////////////////////////////////////////////////////////////
470 // ProcessSingleton::LinuxWatcher 484 // ProcessSingleton::LinuxWatcher
471 // A helper class for a Linux specific implementation of the process singleton. 485 // A helper class for a Linux specific implementation of the process singleton.
472 // This class sets up a listener on the singleton socket and handles parsing 486 // This class sets up a listener on the singleton socket and handles parsing
473 // messages that come in on the singleton socket. 487 // messages that come in on the singleton socket.
474 class ProcessSingleton::LinuxWatcher 488 class ProcessSingleton::LinuxWatcher
475 : public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher, 489 : public base::RefCountedThreadSafe<ProcessSingleton::LinuxWatcher,
476 BrowserThread::DeleteOnIOThread> { 490 BrowserThread::DeleteOnIOThread> {
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
769 std::string hostname; 783 std::string hostname;
770 int pid; 784 int pid;
771 if (!ParseLockPath(lock_path_, &hostname, &pid)) { 785 if (!ParseLockPath(lock_path_, &hostname, &pid)) {
772 // No lockfile exists. 786 // No lockfile exists.
773 return PROCESS_NONE; 787 return PROCESS_NONE;
774 } 788 }
775 789
776 if (hostname.empty()) { 790 if (hostname.empty()) {
777 // Invalid lockfile. 791 // Invalid lockfile.
778 UnlinkPath(lock_path_); 792 UnlinkPath(lock_path_);
793 SendRemoteProcessInteractionResultHistogram(INVALID_LOCK_FILE);
779 return PROCESS_NONE; 794 return PROCESS_NONE;
780 } 795 }
781 796
782 if (hostname != net::GetHostName() && !IsChromeProcess(pid)) { 797 if (hostname != net::GetHostName() && !IsChromeProcess(pid)) {
783 // Locked by process on another host. If the user selected to unlock 798 // Locked by process on another host. If the user selected to unlock
784 // the profile, try to continue; otherwise quit. 799 // the profile, try to continue; otherwise quit.
785 if (DisplayProfileInUseError(lock_path_, hostname, pid)) { 800 if (DisplayProfileInUseError(lock_path_, hostname, pid)) {
786 UnlinkPath(lock_path_); 801 UnlinkPath(lock_path_);
802 SendRemoteProcessInteractionResultHistogram(PROFILE_UNLOCKED);
787 return PROCESS_NONE; 803 return PROCESS_NONE;
788 } 804 }
789 return PROFILE_IN_USE; 805 return PROFILE_IN_USE;
790 } 806 }
791 807
792 if (!IsChromeProcess(pid)) { 808 if (!IsChromeProcess(pid)) {
793 // Orphaned lockfile (no process with pid, or non-chrome process.) 809 // Orphaned lockfile (no process with pid, or non-chrome process.)
794 UnlinkPath(lock_path_); 810 UnlinkPath(lock_path_);
811 SendRemoteProcessInteractionResultHistogram(ORPHANED_LOCK_FILE);
795 return PROCESS_NONE; 812 return PROCESS_NONE;
796 } 813 }
797 814
798 if (IsSameChromeInstance(pid)) { 815 if (IsSameChromeInstance(pid)) {
799 // Orphaned lockfile (pid is part of same chrome instance we are, even 816 // Orphaned lockfile (pid is part of same chrome instance we are, even
800 // though we haven't tried to create a lockfile yet). 817 // though we haven't tried to create a lockfile yet).
801 UnlinkPath(lock_path_); 818 UnlinkPath(lock_path_);
819 SendRemoteProcessInteractionResultHistogram(SAME_BROWSER_INSTANCE);
802 return PROCESS_NONE; 820 return PROCESS_NONE;
803 } 821 }
804 822
805 if (retries == retry_attempts) { 823 if (retries == retry_attempts) {
806 // Retries failed. Kill the unresponsive chrome process and continue. 824 // Retries failed. Kill the unresponsive chrome process and continue.
807 if (!kill_unresponsive || !KillProcessByLockPath()) 825 if (!kill_unresponsive || !KillProcessByLockPath())
808 return PROFILE_IN_USE; 826 return PROFILE_IN_USE;
827 SendRemoteHungProcessTerminateReasonHistogram(NOTIFY_ATTEMPTS_EXCEEDED);
809 return PROCESS_NONE; 828 return PROCESS_NONE;
810 } 829 }
811 830
812 base::PlatformThread::Sleep(sleep_interval); 831 base::PlatformThread::Sleep(sleep_interval);
813 } 832 }
814 833
815 timeval socket_timeout = TimeDeltaToTimeVal(timeout); 834 timeval socket_timeout = TimeDeltaToTimeVal(timeout);
816 setsockopt(socket.fd(), 835 setsockopt(socket.fd(),
817 SOL_SOCKET, 836 SOL_SOCKET,
818 SO_SNDTIMEO, 837 SO_SNDTIMEO,
(...skipping 15 matching lines...) Expand all
834 it != argv.end(); ++it) { 853 it != argv.end(); ++it) {
835 to_send.push_back(kTokenDelimiter); 854 to_send.push_back(kTokenDelimiter);
836 to_send.append(*it); 855 to_send.append(*it);
837 } 856 }
838 857
839 // Send the message 858 // Send the message
840 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) { 859 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) {
841 // Try to kill the other process, because it might have been dead. 860 // Try to kill the other process, because it might have been dead.
842 if (!kill_unresponsive || !KillProcessByLockPath()) 861 if (!kill_unresponsive || !KillProcessByLockPath())
843 return PROFILE_IN_USE; 862 return PROFILE_IN_USE;
863 SendRemoteHungProcessTerminateReasonHistogram(SOCKET_WRITE_FAILED);
844 return PROCESS_NONE; 864 return PROCESS_NONE;
845 } 865 }
846 866
847 if (shutdown(socket.fd(), SHUT_WR) < 0) 867 if (shutdown(socket.fd(), SHUT_WR) < 0)
848 PLOG(ERROR) << "shutdown() failed"; 868 PLOG(ERROR) << "shutdown() failed";
849 869
850 // Read ACK message from the other process. It might be blocked for a certain 870 // 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. 871 // timeout, to make sure the other process has enough time to return ACK.
852 char buf[kMaxACKMessageLength + 1]; 872 char buf[kMaxACKMessageLength + 1];
853 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout); 873 ssize_t len = ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout);
854 874
855 // Failed to read ACK, the other process might have been frozen. 875 // Failed to read ACK, the other process might have been frozen.
856 if (len <= 0) { 876 if (len <= 0) {
857 if (!kill_unresponsive || !KillProcessByLockPath()) 877 if (!kill_unresponsive || !KillProcessByLockPath())
858 return PROFILE_IN_USE; 878 return PROFILE_IN_USE;
879 SendRemoteHungProcessTerminateReasonHistogram(SOCKET_READ_FAILED);
859 return PROCESS_NONE; 880 return PROCESS_NONE;
860 } 881 }
861 882
862 buf[len] = '\0'; 883 buf[len] = '\0';
863 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { 884 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
864 // The other process is shutting down, it's safe to start a new process. 885 // The other process is shutting down, it's safe to start a new process.
886 SendRemoteProcessInteractionResultHistogram(REMOTE_PROCESS_SHUTTING_DOWN);
865 return PROCESS_NONE; 887 return PROCESS_NONE;
866 } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) { 888 } else if (strncmp(buf, kACKToken, arraysize(kACKToken) - 1) == 0) {
867 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS) 889 #if defined(TOOLKIT_VIEWS) && defined(OS_LINUX) && !defined(OS_CHROMEOS)
868 // Likely NULL in unit tests. 890 // Likely NULL in unit tests.
869 views::LinuxUI* linux_ui = views::LinuxUI::instance(); 891 views::LinuxUI* linux_ui = views::LinuxUI::instance();
870 if (linux_ui) 892 if (linux_ui)
871 linux_ui->NotifyWindowManagerStartupComplete(); 893 linux_ui->NotifyWindowManagerStartupComplete();
872 #endif 894 #endif
873 895
874 // Assume the other process is handling the request. 896 // Assume the other process is handling the request.
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
1050 } 1072 }
1051 return true; 1073 return true;
1052 } 1074 }
1053 1075
1054 bool ProcessSingleton::KillProcessByLockPath() { 1076 bool ProcessSingleton::KillProcessByLockPath() {
1055 std::string hostname; 1077 std::string hostname;
1056 int pid; 1078 int pid;
1057 ParseLockPath(lock_path_, &hostname, &pid); 1079 ParseLockPath(lock_path_, &hostname, &pid);
1058 1080
1059 if (!hostname.empty() && hostname != net::GetHostName()) { 1081 if (!hostname.empty() && hostname != net::GetHostName()) {
1060 return DisplayProfileInUseError(lock_path_, hostname, pid); 1082 bool res = DisplayProfileInUseError(lock_path_, hostname, pid);
1083 if (res)
1084 SendRemoteProcessInteractionResultHistogram(PROFILE_UNLOCKED);
gab 2017/05/12 18:40:59 Feels wrong to share histogram for two different c
Alexey Seren 2017/05/15 08:40:48 Acknowledged.
1085 return res;
1061 } 1086 }
1062 UnlinkPath(lock_path_); 1087 UnlinkPath(lock_path_);
1063 1088
1064 if (IsSameChromeInstance(pid)) 1089 if (IsSameChromeInstance(pid)) {
1090 SendRemoteProcessInteractionResultHistogram(SAME_BROWSER_INSTANCE);
gab 2017/05/12 18:40:59 ditto
Alexey Seren 2017/05/15 08:40:48 Acknowledged.
1065 return true; 1091 return true;
1092 }
1066 1093
1067 if (pid > 0) { 1094 if (pid > 0) {
1068 kill_callback_.Run(pid); 1095 kill_callback_.Run(pid);
1069 return true; 1096 return true;
1070 } 1097 }
1071 1098
1099 SendRemoteProcessInteractionResultHistogram(FAILED_TO_EXTRACT_PID);
1100
1072 LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value(); 1101 LOG(ERROR) << "Failed to extract pid from path: " << lock_path_.value();
1073 return true; 1102 return true;
1074 } 1103 }
1075 1104
1076 void ProcessSingleton::KillProcess(int pid) { 1105 void ProcessSingleton::KillProcess(int pid) {
1077 // TODO(james.su@gmail.com): Is SIGKILL ok? 1106 // TODO(james.su@gmail.com): Is SIGKILL ok?
1078 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); 1107 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
1079 // ESRCH = No Such Process (can happen if the other process is already in 1108 // 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). 1109 // progress of shutting down and finishes before we try to kill it).
1081 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 1110 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
1082 << base::safe_strerror(errno); 1111 << base::safe_strerror(errno);
1112
1113 int error_code = (rv == 0) ? 0 : errno;
1114 UMA_HISTOGRAM_SPARSE_SLOWLY(
1115 "Chrome.ProcessSingleton.TerminateProcessErrorCode.Posix", error_code);
1116
1117 RemoteProcessInteractionResult action = TERMINATE_SUCCEEDED;
1118 if (rv != 0) {
1119 switch (error_code) {
1120 case ESRCH:
1121 action = REMOTE_PROCESS_NOT_FOUND;
1122 break;
1123 case EPERM:
1124 action = TERMINATE_NOT_ENOUGH_PERMISSIONS;
1125 break;
1126 default:
1127 action = TERMINATE_FAILED;
1128 break;
1129 }
1130 }
1131 SendRemoteProcessInteractionResultHistogram(action);
1083 } 1132 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698