summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-07 19:46:24 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-07 19:46:24 +0000
commitf8abf723d5fe8a85fade164dd030d4a13e0c7c29 (patch)
tree1d872fc493cee0c32daa7ea68fc02b8f348d42ac
parent8c728c0d72d060bb9d8ad74c066783215b36b087 (diff)
downloadchromium_src-f8abf723d5fe8a85fade164dd030d4a13e0c7c29.zip
chromium_src-f8abf723d5fe8a85fade164dd030d4a13e0c7c29.tar.gz
chromium_src-f8abf723d5fe8a85fade164dd030d4a13e0c7c29.tar.bz2
Start at cleaning up BrowserMain().
BUG=none (or is there?) TEST=trybots and tests Review URL: http://codereview.chromium.org/2234006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51763 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_main.cc544
-rw-r--r--chrome/browser/browser_main.h92
-rw-r--r--chrome/browser/browser_main_posix.cc228
-rw-r--r--chrome/browser/browser_main_win.cc21
-rw-r--r--chrome/chrome_browser.gypi1
5 files changed, 525 insertions, 361 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc
index 77caa2c..4ba9615 100644
--- a/chrome/browser/browser_main.cc
+++ b/chrome/browser/browser_main.cc
@@ -24,12 +24,11 @@
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/time.h"
-#include "base/tracked_objects.h"
#include "base/values.h"
#include "build/build_config.h"
+#include "chrome/browser/browser.h"
#include "chrome/browser/browser_main_win.h"
#include "chrome/browser/browser_init.h"
-#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_prefs.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_impl.h"
@@ -81,15 +80,6 @@
#include "net/socket/client_socket_pool_base.h"
#include "net/spdy/spdy_session_pool.h"
-#if defined(OS_POSIX)
-// TODO(port): get rid of this include. It's used just to provide declarations
-// and stub definitions for classes we encouter during the porting effort.
-#include <errno.h>
-#include <signal.h>
-#include <sys/resource.h>
-#include "base/eintr_wrapper.h"
-#endif
-
#if defined(USE_LINUX_BREAKPAD)
#include "base/linux_util.h"
#include "chrome/app/breakpad_linux.h"
@@ -133,7 +123,6 @@
#include "chrome/installer/util/version.h"
#include "net/base/net_util.h"
#include "net/base/sdch_manager.h"
-#include "net/base/winsock_init.h"
#include "net/socket/ssl_client_socket_nss_factory.h"
#include "printing/printed_document.h"
#include "sandbox/src/sandbox.h"
@@ -164,6 +153,178 @@
#include "chrome/browser/views/browser_dialogs.h"
#endif
+// BrowserMainParts ------------------------------------------------------------
+
+BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters)
+ : parameters_(parameters),
+ parsed_command_line_(parameters.command_line_) {
+}
+
+// BrowserMainParts: EarlyInitialization() and related -------------------------
+
+void BrowserMainParts::EarlyInitialization() {
+ PreEarlyInitialization();
+
+ ConnectionFieldTrial();
+ SocketTimeoutFieldTrial();
+ SpdyFieldTrial();
+ InitializeSSL(); // TODO(viettrungluu): move to platform-specific method(s)
+
+ PostEarlyInitialization();
+}
+
+// This is an A/B test for the maximum number of persistent connections per
+// host. Currently Chrome, Firefox, and IE8 have this value set at 6. Safari
+// uses 4, and Fasterfox (a plugin for Firefox that supposedly configures it to
+// run faster) uses 8. We would like to see how much of an effect this value has
+// on browsing. Too large a value might cause us to run into SYN flood detection
+// mechanisms.
+void BrowserMainParts::ConnectionFieldTrial() {
+ const FieldTrial::Probability kConnDivisor = 100;
+ const FieldTrial::Probability kConn16 = 10; // 10% probability
+ const FieldTrial::Probability kRemainingConn = 30; // 30% probability
+
+ scoped_refptr<FieldTrial> conn_trial =
+ new FieldTrial("ConnCountImpact", kConnDivisor);
+
+ const int conn_16 = conn_trial->AppendGroup("_conn_count_16", kConn16);
+ const int conn_4 = conn_trial->AppendGroup("_conn_count_4", kRemainingConn);
+ const int conn_8 = conn_trial->AppendGroup("_conn_count_8", kRemainingConn);
+ const int conn_6 = conn_trial->AppendGroup("_conn_count_6",
+ FieldTrial::kAllRemainingProbability);
+
+ const int conn_trial_grp = conn_trial->group();
+
+ if (conn_trial_grp == conn_4) {
+ net::HttpNetworkSession::set_max_sockets_per_group(4);
+ } else if (conn_trial_grp == conn_6) {
+ // This (6) is the current default value.
+ net::HttpNetworkSession::set_max_sockets_per_group(6);
+ } else if (conn_trial_grp == conn_8) {
+ net::HttpNetworkSession::set_max_sockets_per_group(8);
+ } else if (conn_trial_grp == conn_16) {
+ net::HttpNetworkSession::set_max_sockets_per_group(16);
+ } else {
+ NOTREACHED();
+ }
+}
+
+// A/B test for determining a value for unused socket timeout. Currently the
+// timeout defaults to 10 seconds. Having this value set too low won't allow us
+// to take advantage of idle sockets. Setting it to too high could possibly
+// result in more ERR_CONNECT_RESETs, requiring one RTT to receive the RST
+// packet and possibly another RTT to re-establish the connection.
+void BrowserMainParts::SocketTimeoutFieldTrial() {
+ const FieldTrial::Probability kIdleSktToDivisor = 100; // Idle socket timeout
+ const FieldTrial::Probability kSktToProb = 25; // 25% probability
+
+ scoped_refptr<FieldTrial> socket_timeout_trial =
+ new FieldTrial("IdleSktToImpact", kIdleSktToDivisor);
+
+ const int socket_timeout_5 =
+ socket_timeout_trial->AppendGroup("_idle_timeout_5", kSktToProb);
+ const int socket_timeout_10 =
+ socket_timeout_trial->AppendGroup("_idle_timeout_10", kSktToProb);
+ const int socket_timeout_20 =
+ socket_timeout_trial->AppendGroup("_idle_timeout_20", kSktToProb);
+ const int socket_timeout_60 =
+ socket_timeout_trial->AppendGroup("_idle_timeout_60",
+ FieldTrial::kAllRemainingProbability);
+
+ const int idle_to_trial_grp = socket_timeout_trial->group();
+
+ if (idle_to_trial_grp == socket_timeout_5) {
+ net::ClientSocketPool::set_unused_idle_socket_timeout(5);
+ } else if (idle_to_trial_grp == socket_timeout_10) {
+ // This (10 seconds) is the current default value.
+ net::ClientSocketPool::set_unused_idle_socket_timeout(10);
+ } else if (idle_to_trial_grp == socket_timeout_20) {
+ net::ClientSocketPool::set_unused_idle_socket_timeout(20);
+ } else if (idle_to_trial_grp == socket_timeout_60) {
+ net::ClientSocketPool::set_unused_idle_socket_timeout(60);
+ } else {
+ NOTREACHED();
+ }
+}
+
+// When --use-spdy not set, users will be in A/B test for spdy.
+// group A (_npn_with_spdy): this means npn and spdy are enabled. In case server
+// supports spdy, browser will use spdy.
+// group B (_npn_with_http): this means npn is enabled but spdy won't be used.
+// Http is still used for all requests.
+// default group: no npn or spdy is involved. The "old" non-spdy
+// chrome behavior.
+void BrowserMainParts::SpdyFieldTrial() {
+ bool is_spdy_trial = false;
+ if (parsed_command_line().HasSwitch(switches::kUseSpdy)) {
+ std::string spdy_mode =
+ parsed_command_line().GetSwitchValueASCII(switches::kUseSpdy);
+ net::HttpNetworkLayer::EnableSpdy(spdy_mode);
+ } else {
+ const FieldTrial::Probability kSpdyDivisor = 1000;
+ // TODO(lzheng): Increase these values to enable more spdy tests.
+ // To enable 100% npn_with_spdy, set npnhttp_probability = 0 and set
+ // npnspdy_probability = FieldTrial::kAllRemainingProbability.
+ FieldTrial::Probability npnhttp_probability = 250; // 25%
+ FieldTrial::Probability npnspdy_probability = 250; // 25%
+#if defined(OS_WIN)
+ // Enable the A/B test for SxS. SxS is only available on windows
+ std::wstring channel;
+ if (BrowserDistribution::GetDistribution()->GetChromeChannel(&channel) &&
+ channel == GoogleChromeSxSDistribution::ChannelName()) {
+ npnhttp_probability = 500;
+ npnspdy_probability = 500;
+ }
+#endif
+ scoped_refptr<FieldTrial> trial =
+ new FieldTrial("SpdyImpact", kSpdyDivisor);
+ // npn with only http support, no spdy.
+ int npn_http_grp =
+ trial->AppendGroup("_npn_with_http", npnhttp_probability);
+ // npn with spdy support.
+ int npn_spdy_grp =
+ trial->AppendGroup("_npn_with_spdy", npnspdy_probability);
+ int trial_grp = trial->group();
+ if (trial_grp == npn_http_grp) {
+ is_spdy_trial = true;
+ net::HttpNetworkLayer::EnableSpdy("npn-http");
+ } else if (trial_grp == npn_spdy_grp) {
+ is_spdy_trial = true;
+ net::HttpNetworkLayer::EnableSpdy("npn");
+ } else {
+ CHECK(!is_spdy_trial);
+ }
+ }
+}
+
+// TODO(viettrungluu): move to platform-specific methods
+void BrowserMainParts::InitializeSSL() {
+ // Use NSS for SSL by default.
+#if defined(OS_MACOSX)
+ // The default client socket factory uses NSS for SSL by default on Mac.
+ if (parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
+ net::ClientSocketFactory::SetSSLClientSocketFactory(
+ net::SSLClientSocketMacFactory);
+ } else {
+ // We want to be sure to init NSPR on the main thread.
+ base::EnsureNSPRInit();
+ }
+#elif defined(OS_WIN)
+ // Because of a build system issue (http://crbug.com/43461), the default
+ // client socket factory uses SChannel (the system SSL library) for SSL by
+ // default on Windows.
+ if (!parsed_command_line().HasSwitch(switches::kUseSystemSSL)) {
+ net::ClientSocketFactory::SetSSLClientSocketFactory(
+ net::SSLClientSocketNSSFactory);
+ // We want to be sure to init NSPR on the main thread.
+ base::EnsureNSPRInit();
+ }
+#endif
+}
+
+// -----------------------------------------------------------------------------
+// TODO(viettrungluu): move more/rest of BrowserMain() into above structure
+
namespace {
// This function provides some ways to test crash and assertion handling
@@ -200,140 +361,6 @@ void RunUIMessageLoop(BrowserProcess* browser_process) {
#endif
}
-#if defined(OS_POSIX)
-// See comment in BrowserMain, where sigaction is called.
-void SIGCHLDHandler(int signal) {
-}
-
-int g_shutdown_pipe_write_fd = -1;
-int g_shutdown_pipe_read_fd = -1;
-
-// Common code between SIG{HUP, INT, TERM}Handler.
-void GracefulShutdownHandler(int signal) {
- // Reinstall the default handler. We had one shot at graceful shutdown.
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIG_DFL;
- RAW_CHECK(sigaction(signal, &action, NULL) == 0);
-
- RAW_CHECK(g_shutdown_pipe_write_fd != -1);
- RAW_CHECK(g_shutdown_pipe_read_fd != -1);
- size_t bytes_written = 0;
- do {
- int rv = HANDLE_EINTR(
- write(g_shutdown_pipe_write_fd,
- reinterpret_cast<const char*>(&signal) + bytes_written,
- sizeof(signal) - bytes_written));
- RAW_CHECK(rv >= 0);
- bytes_written += rv;
- } while (bytes_written < sizeof(signal));
-
- RAW_LOG(INFO,
- "Successfully wrote to shutdown pipe, resetting signal handler.");
-}
-
-// See comment in BrowserMain, where sigaction is called.
-void SIGHUPHandler(int signal) {
- RAW_CHECK(signal == SIGHUP);
- RAW_LOG(INFO, "Handling SIGHUP.");
- GracefulShutdownHandler(signal);
-}
-
-// See comment in BrowserMain, where sigaction is called.
-void SIGINTHandler(int signal) {
- RAW_CHECK(signal == SIGINT);
- RAW_LOG(INFO, "Handling SIGINT.");
- GracefulShutdownHandler(signal);
-}
-
-// See comment in BrowserMain, where sigaction is called.
-void SIGTERMHandler(int signal) {
- RAW_CHECK(signal == SIGTERM);
- RAW_LOG(INFO, "Handling SIGTERM.");
- GracefulShutdownHandler(signal);
-}
-
-class ShutdownDetector : public PlatformThread::Delegate {
- public:
- explicit ShutdownDetector(int shutdown_fd);
-
- virtual void ThreadMain();
-
- private:
- const int shutdown_fd_;
-
- DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
-};
-
-ShutdownDetector::ShutdownDetector(int shutdown_fd)
- : shutdown_fd_(shutdown_fd) {
- CHECK_NE(shutdown_fd_, -1);
-}
-
-void ShutdownDetector::ThreadMain() {
- int signal;
- size_t bytes_read = 0;
- ssize_t ret;
- do {
- ret = HANDLE_EINTR(
- read(shutdown_fd_,
- reinterpret_cast<char*>(&signal) + bytes_read,
- sizeof(signal) - bytes_read));
- if (ret < 0) {
- NOTREACHED() << "Unexpected error: " << strerror(errno);
- break;
- } else if (ret == 0) {
- NOTREACHED() << "Unexpected closure of shutdown pipe.";
- break;
- }
- bytes_read += ret;
- } while (bytes_read < sizeof(signal));
-
- LOG(INFO) << "Handling shutdown for signal " << signal << ".";
-
- if (!ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) {
- // Without a UI thread to post the exit task to, there aren't many
- // options. Raise the signal again. The default handler will pick it up
- // and cause an ungraceful exit.
- RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
- kill(getpid(), signal);
-
- // The signal may be handled on another thread. Give that a chance to
- // happen.
- sleep(3);
-
- // We really should be dead by now. For whatever reason, we're not. Exit
- // immediately, with the exit status set to the signal number with bit 8
- // set. On the systems that we care about, this exit status is what is
- // normally used to indicate an exit by this signal's default handler.
- // This mechanism isn't a de jure standard, but even in the worst case, it
- // should at least result in an immediate exit.
- RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
- _exit(signal | (1 << 7));
- }
-}
-
-// Sets the file descriptor soft limit to |max_descriptors| or the OS hard
-// limit, whichever is lower.
-void SetFileDescriptorLimit(unsigned int max_descriptors) {
- struct rlimit limits;
- if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
- unsigned int new_limit = max_descriptors;
- if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
- new_limit = limits.rlim_max;
- }
- limits.rlim_cur = new_limit;
- if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
- PLOG(INFO) << "Failed to set file descriptor limit";
- }
- } else {
- PLOG(INFO) << "Failed to get file descriptor limit";
- }
-}
-#endif
-
void AddFirstRunNewTabs(BrowserInit* browser_init,
const std::vector<GURL>& new_tabs) {
for (std::vector<GURL>::const_iterator it = new_tabs.begin();
@@ -684,6 +711,12 @@ DLLEXPORT void __cdecl RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
// Main routine for running as the Browser process.
int BrowserMain(const MainFunctionParams& parameters) {
+ scoped_ptr<BrowserMainParts>
+ parts(BrowserMainParts::CreateBrowserMainParts(parameters));
+
+ parts->EarlyInitialization();
+
+ // TODO(viettrungluu): put the remainder into BrowserMainParts
const CommandLine& parsed_command_line = parameters.command_line_;
base::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool_;
@@ -694,205 +727,6 @@ int BrowserMain(const MainFunctionParams& parameters) {
// TODO(beng, brettw): someday, break this out into sub functions with well
// defined roles (e.g. pre/post-profile startup, etc).
-#ifdef TRACK_ALL_TASK_OBJECTS
- // Start tracking the creation and deletion of Task instance.
- // This construction MUST be done before main_message_loop, so that it is
- // destroyed after the main_message_loop.
- tracked_objects::AutoTracking tracking_objects;
-#endif
-
-#if defined(OS_POSIX)
- // We need to accept SIGCHLD, even though our handler is a no-op because
- // otherwise we cannot wait on children. (According to POSIX 2001.)
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIGCHLDHandler;
- CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
-
- // If adding to this list of signal handlers, note the new signal probably
- // needs to be reset in child processes. See
- // base/process_util_posix.cc:LaunchApp
-
- // We need to handle SIGTERM, because that is how many POSIX-based distros ask
- // processes to quit gracefully at shutdown time.
- memset(&action, 0, sizeof(action));
- action.sa_handler = SIGTERMHandler;
- CHECK(sigaction(SIGTERM, &action, NULL) == 0);
- // Also handle SIGINT - when the user terminates the browser via Ctrl+C.
- // If the browser process is being debugged, GDB will catch the SIGINT first.
- action.sa_handler = SIGINTHandler;
- CHECK(sigaction(SIGINT, &action, NULL) == 0);
- // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
- // distros send SIGHUP, SIGTERM, and then SIGKILL.
- action.sa_handler = SIGHUPHandler;
- CHECK(sigaction(SIGHUP, &action, NULL) == 0);
-
- const std::string fd_limit_string =
- parsed_command_line.GetSwitchValueASCII(switches::kFileDescriptorLimit);
- int fd_limit = 0;
- if (!fd_limit_string.empty()) {
- StringToInt(fd_limit_string, &fd_limit);
- }
-#if defined(OS_MACOSX)
- // We use quite a few file descriptors for our IPC, and the default limit on
- // the Mac is low (256), so bump it up if there is no explicit override.
- if (fd_limit == 0) {
- fd_limit = 1024;
- }
-#endif // OS_MACOSX
- if (fd_limit > 0) {
- SetFileDescriptorLimit(fd_limit);
- }
-#endif // OS_POSIX
-
-#if defined(OS_WIN)
- // Initialize Winsock.
- net::EnsureWinsockInit();
-#endif // defined(OS_WIN)
-
- // Initialize statistical testing infrastructure for entire browser.
- FieldTrialList field_trial;
-
- // This is an A/B test for the maximum number of persistent connections per
- // host. Currently Chrome, Firefox, and IE8 have this value set at 6.
- // Safari uses 4, and Fasterfox (a plugin for Firefox that supposedly
- // configures it to run faster) uses 8. We would like to see how much of an
- // effect this value has on browsing. Too large a value might cause us to
- // run into SYN flood detection mechanisms.
- const FieldTrial::Probability kConnDivisor = 100;
- const FieldTrial::Probability kConn16 = 10; // 10% probability
- const FieldTrial::Probability kRemainingConn = 30; // 30% probability
-
- scoped_refptr<FieldTrial> conn_trial =
- new FieldTrial("ConnCountImpact", kConnDivisor);
-
- const int conn_16 = conn_trial->AppendGroup("_conn_count_16", kConn16);
- const int conn_4 = conn_trial->AppendGroup("_conn_count_4", kRemainingConn);
- const int conn_8 = conn_trial->AppendGroup("_conn_count_8", kRemainingConn);
- const int conn_6 = conn_trial->AppendGroup("_conn_count_6",
- FieldTrial::kAllRemainingProbability);
-
- const int conn_trial_grp = conn_trial->group();
-
- if (conn_trial_grp == conn_4) {
- net::HttpNetworkSession::set_max_sockets_per_group(4);
- } else if (conn_trial_grp == conn_6) {
- // This (6) is the current default value.
- net::HttpNetworkSession::set_max_sockets_per_group(6);
- } else if (conn_trial_grp == conn_8) {
- net::HttpNetworkSession::set_max_sockets_per_group(8);
- } else if (conn_trial_grp == conn_16) {
- net::HttpNetworkSession::set_max_sockets_per_group(16);
- } else {
- NOTREACHED();
- }
-
- // A/B test for determining a value for unused socket timeout. Currently the
- // timeout defaults to 10 seconds. Having this value set too low won't allow
- // us to take advantage of idle sockets. Setting it to too high could
- // possibly result in more ERR_CONNECT_RESETs, requiring one RTT to receive
- // the RST packet and possibly another RTT to re-establish the connection.
- const FieldTrial::Probability kIdleSktToDivisor = 100; // Idle socket timeout
- const FieldTrial::Probability kSktToProb = 25; // 25% probability
-
- scoped_refptr<FieldTrial> socket_timeout_trial =
- new FieldTrial("IdleSktToImpact", kIdleSktToDivisor);
-
- const int socket_timeout_5 =
- socket_timeout_trial->AppendGroup("_idle_timeout_5", kSktToProb);
- const int socket_timeout_10 =
- socket_timeout_trial->AppendGroup("_idle_timeout_10", kSktToProb);
- const int socket_timeout_20 =
- socket_timeout_trial->AppendGroup("_idle_timeout_20", kSktToProb);
- const int socket_timeout_60 =
- socket_timeout_trial->AppendGroup("_idle_timeout_60",
- FieldTrial::kAllRemainingProbability);
-
- const int idle_to_trial_grp = socket_timeout_trial->group();
-
- if (idle_to_trial_grp == socket_timeout_5) {
- net::ClientSocketPool::set_unused_idle_socket_timeout(5);
- } else if (idle_to_trial_grp == socket_timeout_10) {
- // This (10 seconds) is the current default value.
- net::ClientSocketPool::set_unused_idle_socket_timeout(10);
- } else if (idle_to_trial_grp == socket_timeout_20) {
- net::ClientSocketPool::set_unused_idle_socket_timeout(20);
- } else if (idle_to_trial_grp == socket_timeout_60) {
- net::ClientSocketPool::set_unused_idle_socket_timeout(60);
- } else {
- NOTREACHED();
- }
-
- // When --use-spdy not set, users will be in A/B test for spdy.
- // group A (_npn_with_spdy): this means npn and spdy are enabled. In
- // case server supports spdy, browser will use spdy.
- // group B (_npn_with_http): this means npn is enabled but spdy
- // won't be used. Http is still used for all requests.
- // default group: no npn or spdy is involved. The "old" non-spdy chrome
- // behavior.
- bool is_spdy_trial = false;
- if (parsed_command_line.HasSwitch(switches::kUseSpdy)) {
- std::string spdy_mode =
- parsed_command_line.GetSwitchValueASCII(switches::kUseSpdy);
- net::HttpNetworkLayer::EnableSpdy(spdy_mode);
- } else {
- const FieldTrial::Probability kSpdyDivisor = 1000;
- // TODO(lzheng): Increase these values to enable more spdy tests.
- // To enable 100% npn_with_spdy, set npnhttp_probability = 0 and set
- // npnspdy_probability = FieldTrial::kAllRemainingProbability.
- FieldTrial::Probability npnhttp_probability = 250; // 25%
- FieldTrial::Probability npnspdy_probability = 250; // 25%
-#if defined(OS_WIN)
- // Enable the A/B test for SxS. SxS is only available on windows
- std::wstring channel;
- if (BrowserDistribution::GetDistribution()->GetChromeChannel(&channel) &&
- channel == GoogleChromeSxSDistribution::ChannelName()) {
- npnhttp_probability = 500;
- npnspdy_probability = 500;
- }
-#endif
- scoped_refptr<FieldTrial> trial =
- new FieldTrial("SpdyImpact", kSpdyDivisor);
- // npn with only http support, no spdy.
- int npn_http_grp =
- trial->AppendGroup("_npn_with_http", npnhttp_probability);
- // npn with spdy support.
- int npn_spdy_grp =
- trial->AppendGroup("_npn_with_spdy", npnspdy_probability);
- int trial_grp = trial->group();
- if (trial_grp == npn_http_grp) {
- is_spdy_trial = true;
- net::HttpNetworkLayer::EnableSpdy("npn-http");
- } else if (trial_grp == npn_spdy_grp) {
- is_spdy_trial = true;
- net::HttpNetworkLayer::EnableSpdy("npn");
- } else {
- CHECK(!is_spdy_trial);
- }
- }
-
- // Use NSS for SSL by default.
-#if defined(OS_MACOSX)
- // The default client socket factory uses NSS for SSL by default on Mac.
- if (parsed_command_line.HasSwitch(switches::kUseSystemSSL)) {
- net::ClientSocketFactory::SetSSLClientSocketFactory(
- net::SSLClientSocketMacFactory);
- } else {
- // We want to be sure to init NSPR on the main thread.
- base::EnsureNSPRInit();
- }
-#elif defined(OS_WIN)
- // Because of a build system issue (http://crbug.com/43461), the default
- // client socket factory uses SChannel (the system SSL library) for SSL by
- // default on Windows.
- if (!parsed_command_line.HasSwitch(switches::kUseSystemSSL)) {
- net::ClientSocketFactory::SetSSLClientSocketFactory(
- net::SSLClientSocketNSSFactory);
- // We want to be sure to init NSPR on the main thread.
- base::EnsureNSPRInit();
- }
-#endif
-
// Do platform-specific things (such as finishing initializing Cocoa)
// prior to instantiating the message loop. This could be turned into a
// broadcast notification.
@@ -911,22 +745,9 @@ int BrowserMain(const MainFunctionParams& parameters) {
// Register the main thread by instantiating it, but don't call any methods.
ChromeThread main_thread(ChromeThread::UI, MessageLoop::current());
-#if defined(OS_POSIX)
- int pipefd[2];
- int ret = pipe(pipefd);
- if (ret < 0) {
- PLOG(DFATAL) << "Failed to create pipe";
- } else {
- g_shutdown_pipe_read_fd = pipefd[0];
- g_shutdown_pipe_write_fd = pipefd[1];
- const size_t kShutdownDetectorThreadStackSize = 4096;
- if (!PlatformThread::CreateNonJoinable(
- kShutdownDetectorThreadStackSize,
- new ShutdownDetector(g_shutdown_pipe_read_fd))) {
- LOG(DFATAL) << "Failed to create shutdown detector task.";
- }
- }
-#endif // defined(OS_POSIX)
+
+ // TODO(viettrungluu): temporary while I refactor BrowserMain()
+ parts->TemporaryPosix_1();
FilePath user_data_dir;
#if defined(OS_WIN)
@@ -1041,6 +862,7 @@ int BrowserMain(const MainFunctionParams& parameters) {
first_run_ui_bypass = true;
}
+ // TODO(viettrungluu): why don't we run this earlier?
if (!parsed_command_line.HasSwitch(switches::kNoErrorDialogs))
WarnAboutMinimumSystemRequirements();
diff --git a/chrome/browser/browser_main.h b/chrome/browser/browser_main.h
index d11d4d9..d23a7e5 100644
--- a/chrome/browser/browser_main.h
+++ b/chrome/browser/browser_main.h
@@ -5,9 +5,101 @@
#ifndef CHROME_BROWSER_BROWSER_MAIN_H_
#define CHROME_BROWSER_BROWSER_MAIN_H_
+#include "base/basictypes.h"
+#include "base/field_trial.h"
+#include "base/tracked_objects.h"
+
+class CommandLine;
struct MainFunctionParams;
class MetricsService;
+// BrowserMainParts:
+// This class contains different "stages" to be executed in |BrowserMain()|,
+// mostly initialization. This is made into a class rather than just functions
+// so each stage can create and maintain state. Each part is represented by a
+// single method (e.g., "EarlyInitialization()"), which does the following:
+// - calls a method (e.g., "PreEarlyInitialization()") which individual
+// platforms can override to provide platform-specific code which is to be
+// executed before the common code;
+// - calls various methods for things common to all platforms (for that given
+// stage); and
+// - calls a method (e.g., "PostEarlyInitialization()") for platform-specific
+// code to be called after the common code.
+// As indicated above, platforms should override the default "Pre...()" and
+// "Post...()" methods when necessary; they need not call the superclass's
+// implementation (which is empty).
+//
+// Parts:
+// - EarlyInitialization: things which should be done as soon as possible on
+// program start (such as setting up signal handlers) and things to be done
+// at some generic time before the start of the main message loop.
+// - (more to come)
+class BrowserMainParts {
+ public:
+ // This static method is to be implemented by each platform and should
+ // instantiate the appropriate subclass.
+ static BrowserMainParts* CreateBrowserMainParts(
+ const MainFunctionParams& parameters);
+
+ // Parts to be called by |BrowserMain()|.
+ void EarlyInitialization();
+
+ // TODO(viettrungluu): This currently contains (POSIX) initialization done
+ // later than "EarlyInitialization()" but dependent on it. Once the
+ // refactoring includes that later stage, this should be put in some more
+ // generic platform-dependent method.
+ void TemporaryPosix_1() {}
+
+ protected:
+ explicit BrowserMainParts(const MainFunctionParams& parameters);
+
+ // Methods to be overridden to provide platform-specific code; these
+ // correspond to the "parts" above.
+ virtual void PreEarlyInitialization() {}
+ virtual void PostEarlyInitialization() {}
+
+ // Accessors for data members (below) ----------------------------------------
+ const MainFunctionParams& parameters() const {
+ return parameters_;
+ }
+ const CommandLine& parsed_command_line() const {
+ return parsed_command_line_;
+ }
+
+ private:
+ // Methods for |EarlyInitialization()| ---------------------------------------
+
+ // A/B test for the maximum number of persistent connections per host.
+ void ConnectionFieldTrial();
+
+ // A/B test for determining a value for unused socket timeout.
+ void SocketTimeoutFieldTrial();
+
+ // A/B test for spdy when --use-spdy not set.
+ void SpdyFieldTrial();
+
+ // Used to initialize NSPR where appropriate.
+ void InitializeSSL();
+
+ // Members initialized on construction ---------------------------------------
+
+ const MainFunctionParams& parameters_;
+ const CommandLine& parsed_command_line_;
+
+#if defined(TRACK_ALL_TASK_OBJECTS)
+ // Creating this object starts tracking the creation and deletion of Task
+ // instance. This MUST be done before main_message_loop, so that it is
+ // destroyed after the main_message_loop.
+ tracked_objects::AutoTracking tracking_objects_;
+#endif
+
+ // Statistical testing infrastructure for the entire browser.
+ FieldTrialList field_trial_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
+};
+
+
// Perform platform-specific work that needs to be done before the main
// message loop is created, initialized, and entered.
void WillInitializeMainMessageLoop(const MainFunctionParams& parameters);
diff --git a/chrome/browser/browser_main_posix.cc b/chrome/browser/browser_main_posix.cc
new file mode 100644
index 0000000..f9a5df2
--- /dev/null
+++ b/chrome/browser/browser_main_posix.cc
@@ -0,0 +1,228 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/resource.h>
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_main.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace {
+
+// See comment in |PreEarlyInitialization()|, where sigaction is called.
+void SIGCHLDHandler(int signal) {
+}
+
+int g_shutdown_pipe_write_fd = -1;
+int g_shutdown_pipe_read_fd = -1;
+
+// Common code between SIG{HUP, INT, TERM}Handler.
+void GracefulShutdownHandler(int signal) {
+ // Reinstall the default handler. We had one shot at graceful shutdown.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_DFL;
+ RAW_CHECK(sigaction(signal, &action, NULL) == 0);
+
+ RAW_CHECK(g_shutdown_pipe_write_fd != -1);
+ RAW_CHECK(g_shutdown_pipe_read_fd != -1);
+ size_t bytes_written = 0;
+ do {
+ int rv = HANDLE_EINTR(
+ write(g_shutdown_pipe_write_fd,
+ reinterpret_cast<const char*>(&signal) + bytes_written,
+ sizeof(signal) - bytes_written));
+ RAW_CHECK(rv >= 0);
+ bytes_written += rv;
+ } while (bytes_written < sizeof(signal));
+
+ RAW_LOG(INFO,
+ "Successfully wrote to shutdown pipe, resetting signal handler.");
+}
+
+// See comment in |PreEarlyInitialization()|, where sigaction is called.
+void SIGHUPHandler(int signal) {
+ RAW_CHECK(signal == SIGHUP);
+ RAW_LOG(INFO, "Handling SIGHUP.");
+ GracefulShutdownHandler(signal);
+}
+
+// See comment in |PreEarlyInitialization()|, where sigaction is called.
+void SIGINTHandler(int signal) {
+ RAW_CHECK(signal == SIGINT);
+ RAW_LOG(INFO, "Handling SIGINT.");
+ GracefulShutdownHandler(signal);
+}
+
+// See comment in |PreEarlyInitialization()|, where sigaction is called.
+void SIGTERMHandler(int signal) {
+ RAW_CHECK(signal == SIGTERM);
+ RAW_LOG(INFO, "Handling SIGTERM.");
+ GracefulShutdownHandler(signal);
+}
+
+class ShutdownDetector : public PlatformThread::Delegate {
+ public:
+ explicit ShutdownDetector(int shutdown_fd);
+
+ virtual void ThreadMain();
+
+ private:
+ const int shutdown_fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShutdownDetector);
+};
+
+ShutdownDetector::ShutdownDetector(int shutdown_fd)
+ : shutdown_fd_(shutdown_fd) {
+ CHECK_NE(shutdown_fd_, -1);
+}
+
+void ShutdownDetector::ThreadMain() {
+ int signal;
+ size_t bytes_read = 0;
+ ssize_t ret;
+ do {
+ ret = HANDLE_EINTR(
+ read(shutdown_fd_,
+ reinterpret_cast<char*>(&signal) + bytes_read,
+ sizeof(signal) - bytes_read));
+ if (ret < 0) {
+ NOTREACHED() << "Unexpected error: " << strerror(errno);
+ break;
+ } else if (ret == 0) {
+ NOTREACHED() << "Unexpected closure of shutdown pipe.";
+ break;
+ }
+ bytes_read += ret;
+ } while (bytes_read < sizeof(signal));
+
+ LOG(INFO) << "Handling shutdown for signal " << signal << ".";
+
+ if (!ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableFunction(BrowserList::CloseAllBrowsersAndExit))) {
+ // Without a UI thread to post the exit task to, there aren't many
+ // options. Raise the signal again. The default handler will pick it up
+ // and cause an ungraceful exit.
+ RAW_LOG(WARNING, "No UI thread, exiting ungracefully.");
+ kill(getpid(), signal);
+
+ // The signal may be handled on another thread. Give that a chance to
+ // happen.
+ sleep(3);
+
+ // We really should be dead by now. For whatever reason, we're not. Exit
+ // immediately, with the exit status set to the signal number with bit 8
+ // set. On the systems that we care about, this exit status is what is
+ // normally used to indicate an exit by this signal's default handler.
+ // This mechanism isn't a de jure standard, but even in the worst case, it
+ // should at least result in an immediate exit.
+ RAW_LOG(WARNING, "Still here, exiting really ungracefully.");
+ _exit(signal | (1 << 7));
+ }
+}
+
+// Sets the file descriptor soft limit to |max_descriptors| or the OS hard
+// limit, whichever is lower.
+void SetFileDescriptorLimit(unsigned int max_descriptors) {
+ struct rlimit limits;
+ if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
+ unsigned int new_limit = max_descriptors;
+ if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
+ new_limit = limits.rlim_max;
+ }
+ limits.rlim_cur = new_limit;
+ if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
+ PLOG(INFO) << "Failed to set file descriptor limit";
+ }
+ } else {
+ PLOG(INFO) << "Failed to get file descriptor limit";
+ }
+}
+
+} // namespace
+
+// BrowserMainPartsPosix -------------------------------------------------------
+
+class BrowserMainPartsPosix : public BrowserMainParts {
+ public:
+ explicit BrowserMainPartsPosix(const MainFunctionParams& parameters)
+ : BrowserMainParts(parameters) {}
+
+ protected:
+ virtual void PreEarlyInitialization() {
+ // We need to accept SIGCHLD, even though our handler is a no-op because
+ // otherwise we cannot wait on children. (According to POSIX 2001.)
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIGCHLDHandler;
+ CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
+
+ // If adding to this list of signal handlers, note the new signal probably
+ // needs to be reset in child processes. See
+ // base/process_util_posix.cc:LaunchApp
+
+ // We need to handle SIGTERM, because that is how many POSIX-based distros
+ // ask processes to quit gracefully at shutdown time.
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIGTERMHandler;
+ CHECK(sigaction(SIGTERM, &action, NULL) == 0);
+ // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If
+ // the browser process is being debugged, GDB will catch the SIGINT first.
+ action.sa_handler = SIGINTHandler;
+ CHECK(sigaction(SIGINT, &action, NULL) == 0);
+ // And SIGHUP, for when the terminal disappears. On shutdown, many Linux
+ // distros send SIGHUP, SIGTERM, and then SIGKILL.
+ action.sa_handler = SIGHUPHandler;
+ CHECK(sigaction(SIGHUP, &action, NULL) == 0);
+
+ const std::string fd_limit_string =
+ parsed_command_line().GetSwitchValueASCII(
+ switches::kFileDescriptorLimit);
+ int fd_limit = 0;
+ if (!fd_limit_string.empty()) {
+ StringToInt(fd_limit_string, &fd_limit);
+ }
+#if defined(OS_MACOSX)
+ // We use quite a few file descriptors for our IPC, and the default limit on
+ // the Mac is low (256), so bump it up if there is no explicit override.
+ if (fd_limit == 0) {
+ fd_limit = 1024;
+ }
+#endif // OS_MACOSX
+ if (fd_limit > 0)
+ SetFileDescriptorLimit(fd_limit);
+ }
+
+ void TemporaryPosix_1() {
+ int pipefd[2];
+ int ret = pipe(pipefd);
+ if (ret < 0) {
+ PLOG(DFATAL) << "Failed to create pipe";
+ } else {
+ g_shutdown_pipe_read_fd = pipefd[0];
+ g_shutdown_pipe_write_fd = pipefd[1];
+ const size_t kShutdownDetectorThreadStackSize = 4096;
+ if (!PlatformThread::CreateNonJoinable(
+ kShutdownDetectorThreadStackSize,
+ new ShutdownDetector(g_shutdown_pipe_read_fd))) {
+ LOG(DFATAL) << "Failed to create shutdown detector task.";
+ }
+ }
+ }
+};
+
+// static
+BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
+ const MainFunctionParams& parameters) {
+ return new BrowserMainPartsPosix(parameters);
+}
diff --git a/chrome/browser/browser_main_win.cc b/chrome/browser/browser_main_win.cc
index 0f4fc35..fdfb413 100644
--- a/chrome/browser/browser_main_win.cc
+++ b/chrome/browser/browser_main_win.cc
@@ -29,6 +29,7 @@
#include "chrome/installer/util/shell_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "net/base/winsock_init.h"
#include "views/focus/accelerator_handler.h"
#include "views/window/window.h"
@@ -202,3 +203,23 @@ bool CheckMachineLevelInstall() {
}
return false;
}
+
+// BrowserMainPartsWin ---------------------------------------------------------
+
+class BrowserMainPartsWin : public BrowserMainParts {
+ public:
+ explicit BrowserMainPartsWin(const MainFunctionParams& parameters)
+ : BrowserMainParts(parameters) {}
+
+ protected:
+ virtual void PreEarlyInitialization() {
+ // Initialize Winsock.
+ net::EnsureWinsockInit();
+ }
+};
+
+// static
+BrowserMainParts* BrowserMainParts::CreateBrowserMainParts(
+ const MainFunctionParams& parameters) {
+ return new BrowserMainPartsWin(parameters);
+}
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 801b533..764ffc3 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -269,6 +269,7 @@
'browser/browser_main.cc',
'browser/browser_main_gtk.cc',
'browser/browser_main_mac.mm',
+ 'browser/browser_main_posix.cc',
'browser/browser_main_win.cc',
'browser/browser_main_win.h',
'browser/browser_prefs.cc',