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

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

Issue 11415237: Move many ProcessSingleton methods to "protected" visibility as an upcoming refactoring of ProcessS… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: decouple from https://codereview.chromium.org/11419258/ Created 8 years 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 690 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename); 701 lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
702 cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename); 702 cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename);
703 703
704 kill_callback_ = base::Bind(&ProcessSingleton::KillProcess, 704 kill_callback_ = base::Bind(&ProcessSingleton::KillProcess,
705 base::Unretained(this)); 705 base::Unretained(this));
706 } 706 }
707 707
708 ProcessSingleton::~ProcessSingleton() { 708 ProcessSingleton::~ProcessSingleton() {
709 } 709 }
710 710
711 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate(
712 const NotificationCallback& notification_callback) {
713 return NotifyOtherProcessWithTimeoutOrCreate(
714 *CommandLine::ForCurrentProcess(),
715 notification_callback,
716 kTimeoutInSeconds);
717 }
718
719 void ProcessSingleton::Cleanup() {
720 UnlinkPath(socket_path_);
721 UnlinkPath(cookie_path_);
722 UnlinkPath(lock_path_);
723 }
724
725 void ProcessSingleton::DisablePromptForTesting() {
726 g_disable_prompt = true;
727 }
728
711 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { 729 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
712 return NotifyOtherProcessWithTimeout(*CommandLine::ForCurrentProcess(), 730 return NotifyOtherProcessWithTimeout(*CommandLine::ForCurrentProcess(),
713 kTimeoutInSeconds, 731 kTimeoutInSeconds,
714 true); 732 true);
715 } 733 }
716 734
735 bool ProcessSingleton::Create(
736 const NotificationCallback& notification_callback) {
737 int sock;
738 sockaddr_un addr;
739
740 // The symlink lock is pointed to the hostname and process id, so other
741 // processes can find it out.
742 FilePath symlink_content(base::StringPrintf(
743 "%s%c%u",
744 net::GetHostName().c_str(),
745 kLockDelimiter,
746 current_pid_));
747
748 // Create symbol link before binding the socket, to ensure only one instance
749 // can have the socket open.
750 if (!SymlinkPath(symlink_content, lock_path_)) {
751 // If we failed to create the lock, most likely another instance won the
752 // startup race.
753 return false;
754 }
755
756 // Create the socket file somewhere in /tmp which is usually mounted as a
757 // normal filesystem. Some network filesystems (notably AFS) are screwy and
758 // do not support Unix domain sockets.
759 if (!socket_dir_.CreateUniqueTempDir()) {
760 LOG(ERROR) << "Failed to create socket directory.";
761 return false;
762 }
763 // Setup the socket symlink and the two cookies.
764 FilePath socket_target_path =
765 socket_dir_.path().Append(chrome::kSingletonSocketFilename);
766 FilePath cookie(GenerateCookie());
767 FilePath remote_cookie_path =
768 socket_dir_.path().Append(chrome::kSingletonCookieFilename);
769 UnlinkPath(socket_path_);
770 UnlinkPath(cookie_path_);
771 if (!SymlinkPath(socket_target_path, socket_path_) ||
772 !SymlinkPath(cookie, cookie_path_) ||
773 !SymlinkPath(cookie, remote_cookie_path)) {
774 // We've already locked things, so we can't have lost the startup race,
775 // but something doesn't like us.
776 LOG(ERROR) << "Failed to create symlinks.";
777 if (!socket_dir_.Delete())
778 LOG(ERROR) << "Encountered a problem when deleting socket directory.";
779 return false;
780 }
781
782 SetupSocket(socket_target_path.value(), &sock, &addr);
783
784 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
785 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value();
786 CloseSocket(sock);
787 return false;
788 }
789
790 if (listen(sock, 5) < 0)
791 NOTREACHED() << "listen failed: " << safe_strerror(errno);
792
793 notification_callback_ = notification_callback;
794
795 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
796 BrowserThread::PostTask(
797 BrowserThread::IO,
798 FROM_HERE,
799 base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
800 watcher_.get(),
801 sock));
802
803 return true;
804 }
805
717 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( 806 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
718 const CommandLine& cmd_line, 807 const CommandLine& cmd_line,
719 int timeout_seconds, 808 int timeout_seconds,
720 bool kill_unresponsive) { 809 bool kill_unresponsive) {
721 DCHECK_GE(timeout_seconds, 0); 810 DCHECK_GE(timeout_seconds, 0);
722 811
723 ScopedSocket socket; 812 ScopedSocket socket;
724 for (int retries = 0; retries <= timeout_seconds; ++retries) { 813 for (int retries = 0; retries <= timeout_seconds; ++retries) {
725 // Try to connect to the socket. 814 // Try to connect to the socket.
726 if (ConnectSocket(&socket, socket_path_, cookie_path_)) 815 if (ConnectSocket(&socket, socket_path_, cookie_path_))
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 gdk_notify_startup_complete(); 917 gdk_notify_startup_complete();
829 #endif 918 #endif
830 // Assume the other process is handling the request. 919 // Assume the other process is handling the request.
831 return PROCESS_NOTIFIED; 920 return PROCESS_NOTIFIED;
832 } 921 }
833 922
834 NOTREACHED() << "The other process returned unknown message: " << buf; 923 NOTREACHED() << "The other process returned unknown message: " << buf;
835 return PROCESS_NOTIFIED; 924 return PROCESS_NOTIFIED;
836 } 925 }
837 926
838 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate(
839 const NotificationCallback& notification_callback) {
840 return NotifyOtherProcessWithTimeoutOrCreate(
841 *CommandLine::ForCurrentProcess(),
842 notification_callback,
843 kTimeoutInSeconds);
844 }
845
846 ProcessSingleton::NotifyResult 927 ProcessSingleton::NotifyResult
847 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( 928 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
848 const CommandLine& command_line, 929 const CommandLine& command_line,
849 const NotificationCallback& notification_callback, 930 const NotificationCallback& notification_callback,
850 int timeout_seconds) { 931 int timeout_seconds) {
851 NotifyResult result = NotifyOtherProcessWithTimeout(command_line, 932 NotifyResult result = NotifyOtherProcessWithTimeout(command_line,
852 timeout_seconds, true); 933 timeout_seconds, true);
853 if (result != PROCESS_NONE) 934 if (result != PROCESS_NONE)
854 return result; 935 return result;
855 if (Create(notification_callback)) 936 if (Create(notification_callback))
(...skipping 12 matching lines...) Expand all
868 949
869 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) { 950 void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) {
870 current_pid_ = pid; 951 current_pid_ = pid;
871 } 952 }
872 953
873 void ProcessSingleton::OverrideKillCallbackForTesting( 954 void ProcessSingleton::OverrideKillCallbackForTesting(
874 const base::Callback<void(int)>& callback) { 955 const base::Callback<void(int)>& callback) {
875 kill_callback_ = callback; 956 kill_callback_ = callback;
876 } 957 }
877 958
878 void ProcessSingleton::DisablePromptForTesting() {
879 g_disable_prompt = true;
880 }
881
882 bool ProcessSingleton::Create(
883 const NotificationCallback& notification_callback) {
884 int sock;
885 sockaddr_un addr;
886
887 // The symlink lock is pointed to the hostname and process id, so other
888 // processes can find it out.
889 FilePath symlink_content(base::StringPrintf(
890 "%s%c%u",
891 net::GetHostName().c_str(),
892 kLockDelimiter,
893 current_pid_));
894
895 // Create symbol link before binding the socket, to ensure only one instance
896 // can have the socket open.
897 if (!SymlinkPath(symlink_content, lock_path_)) {
898 // If we failed to create the lock, most likely another instance won the
899 // startup race.
900 return false;
901 }
902
903 // Create the socket file somewhere in /tmp which is usually mounted as a
904 // normal filesystem. Some network filesystems (notably AFS) are screwy and
905 // do not support Unix domain sockets.
906 if (!socket_dir_.CreateUniqueTempDir()) {
907 LOG(ERROR) << "Failed to create socket directory.";
908 return false;
909 }
910 // Setup the socket symlink and the two cookies.
911 FilePath socket_target_path =
912 socket_dir_.path().Append(chrome::kSingletonSocketFilename);
913 FilePath cookie(GenerateCookie());
914 FilePath remote_cookie_path =
915 socket_dir_.path().Append(chrome::kSingletonCookieFilename);
916 UnlinkPath(socket_path_);
917 UnlinkPath(cookie_path_);
918 if (!SymlinkPath(socket_target_path, socket_path_) ||
919 !SymlinkPath(cookie, cookie_path_) ||
920 !SymlinkPath(cookie, remote_cookie_path)) {
921 // We've already locked things, so we can't have lost the startup race,
922 // but something doesn't like us.
923 LOG(ERROR) << "Failed to create symlinks.";
924 if (!socket_dir_.Delete())
925 LOG(ERROR) << "Encountered a problem when deleting socket directory.";
926 return false;
927 }
928
929 SetupSocket(socket_target_path.value(), &sock, &addr);
930
931 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
932 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value();
933 CloseSocket(sock);
934 return false;
935 }
936
937 if (listen(sock, 5) < 0)
938 NOTREACHED() << "listen failed: " << safe_strerror(errno);
939
940 notification_callback_ = notification_callback;
941
942 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
943 BrowserThread::PostTask(
944 BrowserThread::IO,
945 FROM_HERE,
946 base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
947 watcher_.get(),
948 sock));
949
950 return true;
951 }
952
953 void ProcessSingleton::Cleanup() {
954 UnlinkPath(socket_path_);
955 UnlinkPath(cookie_path_);
956 UnlinkPath(lock_path_);
957 }
958
959 bool ProcessSingleton::IsSameChromeInstance(pid_t pid) { 959 bool ProcessSingleton::IsSameChromeInstance(pid_t pid) {
960 pid_t cur_pid = current_pid_; 960 pid_t cur_pid = current_pid_;
961 while (pid != cur_pid) { 961 while (pid != cur_pid) {
962 pid = base::GetParentProcessId(pid); 962 pid = base::GetParentProcessId(pid);
963 if (pid < 0) 963 if (pid < 0)
964 return false; 964 return false;
965 if (!IsChromeProcess(pid)) 965 if (!IsChromeProcess(pid))
966 return false; 966 return false;
967 } 967 }
968 return true; 968 return true;
(...skipping 24 matching lines...) Expand all
993 993
994 void ProcessSingleton::KillProcess(int pid) { 994 void ProcessSingleton::KillProcess(int pid) {
995 // TODO(james.su@gmail.com): Is SIGKILL ok? 995 // TODO(james.su@gmail.com): Is SIGKILL ok?
996 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL); 996 int rv = kill(static_cast<base::ProcessHandle>(pid), SIGKILL);
997 // ESRCH = No Such Process (can happen if the other process is already in 997 // ESRCH = No Such Process (can happen if the other process is already in
998 // progress of shutting down and finishes before we try to kill it). 998 // progress of shutting down and finishes before we try to kill it).
999 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 999 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
1000 << safe_strerror(errno); 1000 << safe_strerror(errno);
1001 } 1001 }
1002 1002
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698