OLD | NEW |
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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 #include "base/safe_strerror_posix.h" | 73 #include "base/safe_strerror_posix.h" |
74 #include "base/stl_util.h" | 74 #include "base/stl_util.h" |
75 #include "base/string_number_conversions.h" | 75 #include "base/string_number_conversions.h" |
76 #include "base/string_split.h" | 76 #include "base/string_split.h" |
77 #include "base/stringprintf.h" | 77 #include "base/stringprintf.h" |
78 #include "base/sys_string_conversions.h" | 78 #include "base/sys_string_conversions.h" |
79 #include "base/threading/platform_thread.h" | 79 #include "base/threading/platform_thread.h" |
80 #include "base/time.h" | 80 #include "base/time.h" |
81 #include "base/timer.h" | 81 #include "base/timer.h" |
82 #include "base/utf_string_conversions.h" | 82 #include "base/utf_string_conversions.h" |
83 #include "chrome/browser/browser_process.h" | |
84 #if defined(TOOLKIT_GTK) | 83 #if defined(TOOLKIT_GTK) |
85 #include "chrome/browser/ui/gtk/process_singleton_dialog.h" | 84 #include "chrome/browser/ui/gtk/process_singleton_dialog.h" |
86 #endif | 85 #endif |
87 #include "chrome/browser/io_thread.h" | |
88 #include "chrome/browser/profiles/profile.h" | |
89 #include "chrome/browser/profiles/profile_manager.h" | |
90 #include "chrome/browser/ui/browser_init.h" | |
91 #include "chrome/common/chrome_constants.h" | 86 #include "chrome/common/chrome_constants.h" |
92 #include "chrome/common/chrome_paths.h" | |
93 #include "chrome/common/chrome_switches.h" | 87 #include "chrome/common/chrome_switches.h" |
94 #include "content/public/browser/browser_thread.h" | 88 #include "content/public/browser/browser_thread.h" |
95 #include "grit/chromium_strings.h" | 89 #include "grit/chromium_strings.h" |
96 #include "grit/generated_resources.h" | 90 #include "grit/generated_resources.h" |
97 #include "net/base/net_util.h" | 91 #include "net/base/net_util.h" |
98 #include "ui/base/l10n/l10n_util.h" | 92 #include "ui/base/l10n/l10n_util.h" |
99 | 93 |
100 using content::BrowserThread; | 94 using content::BrowserThread; |
101 | 95 |
102 const int ProcessSingleton::kTimeoutInSeconds; | 96 const int ProcessSingleton::kTimeoutInSeconds; |
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 // we are probably in a first run critical phase. | 617 // we are probably in a first run critical phase. |
624 if (parent_->locked()) { | 618 if (parent_->locked()) { |
625 DLOG(WARNING) << "Browser is locked"; | 619 DLOG(WARNING) << "Browser is locked"; |
626 parent_->saved_startup_messages_.push_back( | 620 parent_->saved_startup_messages_.push_back( |
627 std::make_pair(argv, FilePath(current_dir))); | 621 std::make_pair(argv, FilePath(current_dir))); |
628 // Send back "ACK" message to prevent the client process from starting up. | 622 // Send back "ACK" message to prevent the client process from starting up. |
629 reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1); | 623 reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1); |
630 return; | 624 return; |
631 } | 625 } |
632 | 626 |
633 // Ignore the request if the browser process is already in shutdown path. | 627 if (parent_->notification_callback_.Run(CommandLine(argv), |
634 if (!g_browser_process || g_browser_process->IsShuttingDown()) { | 628 FilePath(current_dir))) { |
| 629 // Send back "ACK" message to prevent the client process from starting up. |
| 630 reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1); |
| 631 } else { |
635 LOG(WARNING) << "Not handling interprocess notification as browser" | 632 LOG(WARNING) << "Not handling interprocess notification as browser" |
636 " is shutting down"; | 633 " is shutting down"; |
637 // Send back "SHUTDOWN" message, so that the client process can start up | 634 // Send back "SHUTDOWN" message, so that the client process can start up |
638 // without killing this process. | 635 // without killing this process. |
639 reader->FinishWithACK(kShutdownToken, arraysize(kShutdownToken) - 1); | 636 reader->FinishWithACK(kShutdownToken, arraysize(kShutdownToken) - 1); |
640 return; | 637 return; |
641 } | 638 } |
642 | |
643 CommandLine parsed_command_line(argv); | |
644 parent_->ProcessCommandLine(parsed_command_line, FilePath(current_dir)); | |
645 | |
646 // Send back "ACK" message to prevent the client process from starting up. | |
647 reader->FinishWithACK(kACKToken, arraysize(kACKToken) - 1); | |
648 } | 639 } |
649 | 640 |
650 void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) { | 641 void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) { |
651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 642 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
652 DCHECK(reader); | 643 DCHECK(reader); |
653 readers_.erase(reader); | 644 readers_.erase(reader); |
654 delete reader; | 645 delete reader; |
655 } | 646 } |
656 | 647 |
657 /////////////////////////////////////////////////////////////////////////////// | 648 /////////////////////////////////////////////////////////////////////////////// |
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
879 gdk_notify_startup_complete(); | 870 gdk_notify_startup_complete(); |
880 #endif | 871 #endif |
881 // Assume the other process is handling the request. | 872 // Assume the other process is handling the request. |
882 return PROCESS_NOTIFIED; | 873 return PROCESS_NOTIFIED; |
883 } | 874 } |
884 | 875 |
885 NOTREACHED() << "The other process returned unknown message: " << buf; | 876 NOTREACHED() << "The other process returned unknown message: " << buf; |
886 return PROCESS_NOTIFIED; | 877 return PROCESS_NOTIFIED; |
887 } | 878 } |
888 | 879 |
889 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() { | 880 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate( |
| 881 const NotificationCallback& notification_callback) { |
890 return NotifyOtherProcessWithTimeoutOrCreate( | 882 return NotifyOtherProcessWithTimeoutOrCreate( |
891 *CommandLine::ForCurrentProcess(), | 883 *CommandLine::ForCurrentProcess(), |
| 884 notification_callback, |
892 kTimeoutInSeconds); | 885 kTimeoutInSeconds); |
893 } | 886 } |
894 | 887 |
895 ProcessSingleton::NotifyResult | 888 ProcessSingleton::NotifyResult |
896 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( | 889 ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( |
897 const CommandLine& command_line, | 890 const CommandLine& command_line, |
| 891 const NotificationCallback& notification_callback, |
898 int timeout_seconds) { | 892 int timeout_seconds) { |
899 NotifyResult result = NotifyOtherProcessWithTimeout(command_line, | 893 NotifyResult result = NotifyOtherProcessWithTimeout(command_line, |
900 timeout_seconds, true); | 894 timeout_seconds, true); |
901 if (result != PROCESS_NONE) | 895 if (result != PROCESS_NONE) |
902 return result; | 896 return result; |
903 if (Create()) | 897 if (Create(notification_callback)) |
904 return PROCESS_NONE; | 898 return PROCESS_NONE; |
905 // If the Create() failed, try again to notify. (It could be that another | 899 // If the Create() failed, try again to notify. (It could be that another |
906 // instance was starting at the same time and managed to grab the lock before | 900 // instance was starting at the same time and managed to grab the lock before |
907 // we did.) | 901 // we did.) |
908 // This time, we don't want to kill anything if we aren't successful, since we | 902 // This time, we don't want to kill anything if we aren't successful, since we |
909 // aren't going to try to take over the lock ourselves. | 903 // aren't going to try to take over the lock ourselves. |
910 result = NotifyOtherProcessWithTimeout(command_line, timeout_seconds, false); | 904 result = NotifyOtherProcessWithTimeout(command_line, timeout_seconds, false); |
911 if (result != PROCESS_NONE) | 905 if (result != PROCESS_NONE) |
912 return result; | 906 return result; |
913 | 907 |
914 return LOCK_ERROR; | 908 return LOCK_ERROR; |
915 } | 909 } |
916 | 910 |
917 bool ProcessSingleton::Create() { | 911 bool ProcessSingleton::Create( |
| 912 const NotificationCallback& notification_callback) { |
918 int sock; | 913 int sock; |
919 sockaddr_un addr; | 914 sockaddr_un addr; |
920 | 915 |
921 // The symlink lock is pointed to the hostname and process id, so other | 916 // The symlink lock is pointed to the hostname and process id, so other |
922 // processes can find it out. | 917 // processes can find it out. |
923 FilePath symlink_content(base::StringPrintf( | 918 FilePath symlink_content(base::StringPrintf( |
924 "%s%c%u", | 919 "%s%c%u", |
925 net::GetHostName().c_str(), | 920 net::GetHostName().c_str(), |
926 kLockDelimiter, | 921 kLockDelimiter, |
927 base::GetCurrentProcId())); | 922 base::GetCurrentProcId())); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
964 | 959 |
965 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { | 960 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { |
966 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value(); | 961 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value(); |
967 CloseSocket(sock); | 962 CloseSocket(sock); |
968 return false; | 963 return false; |
969 } | 964 } |
970 | 965 |
971 if (listen(sock, 5) < 0) | 966 if (listen(sock, 5) < 0) |
972 NOTREACHED() << "listen failed: " << safe_strerror(errno); | 967 NOTREACHED() << "listen failed: " << safe_strerror(errno); |
973 | 968 |
| 969 notification_callback_ = notification_callback; |
| 970 |
974 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO)); | 971 DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO)); |
975 BrowserThread::PostTask( | 972 BrowserThread::PostTask( |
976 BrowserThread::IO, | 973 BrowserThread::IO, |
977 FROM_HERE, | 974 FROM_HERE, |
978 base::Bind(&ProcessSingleton::LinuxWatcher::StartListening, | 975 base::Bind(&ProcessSingleton::LinuxWatcher::StartListening, |
979 watcher_.get(), | 976 watcher_.get(), |
980 sock)); | 977 sock)); |
981 | 978 |
982 return true; | 979 return true; |
983 } | 980 } |
984 | 981 |
985 void ProcessSingleton::Cleanup() { | 982 void ProcessSingleton::Cleanup() { |
986 UnlinkPath(socket_path_); | 983 UnlinkPath(socket_path_); |
987 UnlinkPath(cookie_path_); | 984 UnlinkPath(cookie_path_); |
988 UnlinkPath(lock_path_); | 985 UnlinkPath(lock_path_); |
989 } | 986 } |
990 | |
991 void ProcessSingleton::ProcessCommandLine(const CommandLine& command_line, | |
992 const FilePath& current_directory) { | |
993 PrefService* prefs = g_browser_process->local_state(); | |
994 DCHECK(prefs); | |
995 | |
996 // Ignore the request if the process was passed the --product-version flag. | |
997 // Normally we wouldn't get here if that flag had been passed, but it can | |
998 // happen if it is passed to an older version of chrome. Since newer versions | |
999 // of chrome do this in the background, we want to avoid spawning extra | |
1000 // windows. | |
1001 if (command_line.HasSwitch(switches::kProductVersion)) { | |
1002 DLOG(WARNING) << "Remote process was passed product version flag, " | |
1003 << "but ignored it. Doing nothing."; | |
1004 } else { | |
1005 // Run the browser startup sequence again, with the command line of the | |
1006 // signalling process. | |
1007 BrowserInit::ProcessCommandLineAlreadyRunning(command_line, | |
1008 current_directory); | |
1009 } | |
1010 } | |
OLD | NEW |