| 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 |