Commit 4bb76029 authored by tony@chromium.org's avatar tony@chromium.org

Refactor browser_main.cc.

Move the anonymous namespace above BrowserMainParts.


Review URL: http://codereview.chromium.org/7634006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96501 0039d316-1c4b-4281-b951-d872f2087c98
parent d03a7e7a
......@@ -217,1062 +217,1056 @@ class NetLog;
} // namespace net
namespace {
void SetSocketReusePolicy(int warmest_socket_trial_group,
const int socket_policy[],
int num_groups);
} // namespace
// BrowserMainParts ------------------------------------------------------------
// This function provides some ways to test crash and assertion handling
// behavior of the program.
void HandleTestParameters(const CommandLine& command_line) {
// This parameter causes an assertion.
if (command_line.HasSwitch(switches::kBrowserAssertTest)) {
DCHECK(false);
}
BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters)
: parameters_(parameters),
parsed_command_line_(parameters.command_line_) {
}
// This parameter causes a null pointer crash (crash reporter trigger).
if (command_line.HasSwitch(switches::kBrowserCrashTest)) {
int* bad_pointer = NULL;
*bad_pointer = 0;
}
BrowserMainParts::~BrowserMainParts() {
#if defined(OS_CHROMEOS)
// Test loading libcros and exit. We return 0 if the library could be loaded,
// and 1 if it can't be. This is for validation that the library is installed
// and versioned properly for Chrome to find.
if (command_line.HasSwitch(switches::kTestLoadLibcros))
exit(!chromeos::CrosLibrary::Get()->EnsureLoaded());
#endif
}
// BrowserMainParts: |EarlyInitialization()| and related -----------------------
void RunUIMessageLoop(BrowserProcess* browser_process) {
TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
// This should be invoked as close to the start of the browser's
// UI thread message loop as possible to get a stable measurement
// across versions.
RecordBrowserStartupTime();
void BrowserMainParts::EarlyInitialization() {
PreEarlyInitialization();
// If the UI thread blocks, the whole UI is unresponsive.
// Do not allow disk IO from the UI thread.
base::ThreadRestrictions::SetIOAllowed(false);
if (parsed_command_line().HasSwitch(switches::kEnableBenchmarking))
base::FieldTrial::EnableBenchmarking();
#if defined(TOOLKIT_VIEWS)
views::AcceleratorHandler accelerator_handler;
MessageLoopForUI::current()->Run(&accelerator_handler);
#elif defined(USE_X11)
MessageLoopForUI::current()->Run(NULL);
#elif defined(OS_POSIX)
MessageLoopForUI::current()->Run();
#endif
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("UIMessageLoopEnded",
true);
#endif
InitializeSSL();
TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
}
if (parsed_command_line().HasSwitch(switches::kDisableSSLFalseStart))
net::SSLConfigService::DisableFalseStart();
if (parsed_command_line().HasSwitch(switches::kEnableSSLCachedInfo))
net::SSLConfigService::EnableCachedInfo();
if (parsed_command_line().HasSwitch(switches::kEnableOriginBoundCerts))
net::SSLConfigService::EnableOriginBoundCerts();
if (parsed_command_line().HasSwitch(
switches::kEnableDNSCertProvenanceChecking)) {
net::SSLConfigService::EnableDNSCertProvenanceChecking();
void AddFirstRunNewTabs(BrowserInit* browser_init,
const std::vector<GURL>& new_tabs) {
for (std::vector<GURL>::const_iterator it = new_tabs.begin();
it != new_tabs.end(); ++it) {
if (it->is_valid())
browser_init->AddFirstRunTab(*it);
}
// TODO(abarth): Should this move to InitializeNetworkOptions? This doesn't
// seem dependent on InitializeSSL().
if (parsed_command_line().HasSwitch(switches::kEnableTcpFastOpen))
net::set_tcp_fastopen_enabled(true);
PostEarlyInitialization();
}
// This will be called after the command-line has been mutated by about:flags
MetricsService* BrowserMainParts::SetupMetricsAndFieldTrials(
const CommandLine& parsed_command_line,
PrefService* local_state) {
// Must initialize metrics after labs have been converted into switches,
// but before field trials are set up (so that client ID is available for
// one-time randomized field trials).
MetricsService* metrics = InitializeMetrics(parsed_command_line, local_state);
// Initialize FieldTrialList to support FieldTrials that use one-time
// randomization. The client ID will be empty if the user has not opted
// to send metrics.
field_trial_list_.reset(new base::FieldTrialList(metrics->GetClientId()));
#if defined(USE_LINUX_BREAKPAD)
class GetLinuxDistroTask : public Task {
public:
explicit GetLinuxDistroTask() {}
SetupFieldTrials(metrics->recording_active(),
local_state->IsManagedPreference(
prefs::kMaxConnectionsPerProxy));
virtual void Run() {
base::GetLinuxDistro(); // Initialize base::linux_distro if needed.
}
// Initialize FieldTrialSynchronizer system. This is a singleton and is used
// for posting tasks via NewRunnableMethod. Its deleted when it goes out of
// scope. Even though NewRunnableMethod does AddRef and Release, the object
// will not be deleted after the Task is executed.
field_trial_synchronizer_ = new FieldTrialSynchronizer();
DISALLOW_COPY_AND_ASSIGN(GetLinuxDistroTask);
};
#endif // USE_LINUX_BREAKPAD
return metrics;
}
void InitializeNetworkOptions(const CommandLine& parsed_command_line) {
if (parsed_command_line.HasSwitch(switches::kEnableFileCookies)) {
// Enable cookie storage for file:// URLs. Must do this before the first
// Profile (and therefore the first CookieMonster) is created.
net::CookieMonster::EnableFileScheme();
}
// 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 base::FieldTrial::Probability kConnectDivisor = 100;
const base::FieldTrial::Probability kConnectProbability = 1; // 1% prob.
if (parsed_command_line.HasSwitch(switches::kEnableMacCookies))
net::URLRequest::EnableMacCookies();
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> connect_trial(
new base::FieldTrial(
"ConnCountImpact", kConnectDivisor, "conn_count_6", 2011, 6, 30));
if (parsed_command_line.HasSwitch(switches::kIgnoreCertificateErrors))
net::HttpStreamFactory::set_ignore_certificate_errors(true);
// This (6) is the current default value. Having this group declared here
// makes it straightforward to modify |kConnectProbability| such that the same
// probability value will be assigned to all the other groups, while
// preserving the remainder of the of probability space to the default value.
const int connect_6 = connect_trial->kDefaultGroupNumber;
if (parsed_command_line.HasSwitch(switches::kHostRules))
net::HttpStreamFactory::SetHostMappingRules(
parsed_command_line.GetSwitchValueASCII(switches::kHostRules));
const int connect_5 = connect_trial->AppendGroup("conn_count_5",
kConnectProbability);
const int connect_7 = connect_trial->AppendGroup("conn_count_7",
kConnectProbability);
const int connect_8 = connect_trial->AppendGroup("conn_count_8",
kConnectProbability);
const int connect_9 = connect_trial->AppendGroup("conn_count_9",
kConnectProbability);
if (parsed_command_line.HasSwitch(switches::kEnableIPPooling))
net::SpdySessionPool::enable_ip_pooling(true);
const int connect_trial_group = connect_trial->group();
if (parsed_command_line.HasSwitch(switches::kDisableIPPooling))
net::SpdySessionPool::enable_ip_pooling(false);
if (connect_trial_group == connect_5) {
net::ClientSocketPoolManager::set_max_sockets_per_group(5);
} else if (connect_trial_group == connect_6) {
net::ClientSocketPoolManager::set_max_sockets_per_group(6);
} else if (connect_trial_group == connect_7) {
net::ClientSocketPoolManager::set_max_sockets_per_group(7);
} else if (connect_trial_group == connect_8) {
net::ClientSocketPoolManager::set_max_sockets_per_group(8);
} else if (connect_trial_group == connect_9) {
net::ClientSocketPoolManager::set_max_sockets_per_group(9);
} else {
NOTREACHED();
if (parsed_command_line.HasSwitch(switches::kMaxSpdySessionsPerDomain)) {
int value;
base::StringToInt(parsed_command_line.GetSwitchValueASCII(
switches::kMaxSpdySessionsPerDomain),
&value);
net::SpdySessionPool::set_max_sessions_per_domain(value);
}
}
// 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_CONNECTION_RESETs, since some servers will kill a socket
// before we time it out. Since these are "unused" sockets, we won't retry the
// connection and instead show an error to the user. So we need to be
// conservative here. We've seen that some servers will close the socket after
// as short as 10 seconds. See http://crbug.com/84313 for more details.
void BrowserMainParts::SocketTimeoutFieldTrial() {
const base::FieldTrial::Probability kIdleSocketTimeoutDivisor = 100;
// 1% probability for all experimental settings.
const base::FieldTrial::Probability kSocketTimeoutProbability = 1;
SetDnsCertProvenanceCheckerFactory(CreateChromeDnsCertProvenanceChecker);
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> socket_timeout_trial(
new base::FieldTrial("IdleSktToImpact", kIdleSocketTimeoutDivisor,
"idle_timeout_10", 2011, 6, 30));
const int socket_timeout_10 = socket_timeout_trial->kDefaultGroupNumber;
if (parsed_command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
// Enable WebSocket over SPDY.
net::WebSocketJob::set_websocket_over_spdy_enabled(true);
}
}
const int socket_timeout_5 =
socket_timeout_trial->AppendGroup("idle_timeout_5",
kSocketTimeoutProbability);
const int socket_timeout_20 =
socket_timeout_trial->AppendGroup("idle_timeout_20",
kSocketTimeoutProbability);
void InitializeURLRequestThrottlerManager(net::NetLog* net_log) {
net::URLRequestThrottlerManager::GetInstance()->set_enable_thread_checks(
true);
const int idle_to_trial_group = socket_timeout_trial->group();
// TODO(joi): Passing the NetLog here is temporary; once I switch the
// URLRequestThrottlerManager to be part of the URLRequestContext it will
// come from there. Doing it this way for now (2011/5/12) to try to fail
// fast in case A/B experiment gives unexpected results.
net::URLRequestThrottlerManager::GetInstance()->set_net_log(net_log);
}
if (idle_to_trial_group == socket_timeout_5) {
net::ClientSocketPool::set_unused_idle_socket_timeout(5);
} else if (idle_to_trial_group == socket_timeout_10) {
net::ClientSocketPool::set_unused_idle_socket_timeout(10);
} else if (idle_to_trial_group == socket_timeout_20) {
net::ClientSocketPool::set_unused_idle_socket_timeout(20);
} else {
NOTREACHED();
}
// Creates key child threads. We need to do this explicitly since
// BrowserThread::PostTask silently deletes a posted task if the target message
// loop isn't created.
void CreateChildThreads(BrowserProcessImpl* process) {
process->db_thread();
process->file_thread();
process->process_launcher_thread();
process->cache_thread();
process->io_thread();
#if defined(OS_CHROMEOS)
process->web_socket_proxy_thread();
#endif
// Create watchdog thread after creating all other threads because it will
// watch the other threads and they must be running.
process->watchdog_thread();
}
void BrowserMainParts::ProxyConnectionsFieldTrial() {
const base::FieldTrial::Probability kProxyConnectionsDivisor = 100;
// 25% probability
const base::FieldTrial::Probability kProxyConnectionProbability = 1;
// Returns the new local state object, guaranteed non-NULL.
PrefService* InitializeLocalState(const CommandLine& parsed_command_line,
bool is_first_run) {
FilePath local_state_path;
PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
bool local_state_file_exists = file_util::PathExists(local_state_path);
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> proxy_connection_trial(
new base::FieldTrial("ProxyConnectionImpact", kProxyConnectionsDivisor,
"proxy_connections_32", 2011, 6, 30));
// Load local state. This includes the application locale so we know which
// locale dll to load.
PrefService* local_state = g_browser_process->local_state();
DCHECK(local_state);
// This (32 connections per proxy server) is the current default value.
// Declaring it here allows us to easily re-assign the probability space while
// maintaining that the default group always has the remainder of the "share",
// which allows for cleaner and quicker changes down the line if needed.
const int proxy_connections_32 = proxy_connection_trial->kDefaultGroupNumber;
// TODO(brettw,*): this comment about ResourceBundle was here since
// initial commit. This comment seems unrelated, bit-rotten and
// a candidate for removal.
// Initialize ResourceBundle which handles files loaded from external
// sources. This has to be done before uninstall code path and before prefs
// are registered.
local_state->RegisterStringPref(prefs::kApplicationLocale, std::string());
#if defined(OS_CHROMEOS)
local_state->RegisterStringPref(prefs::kOwnerLocale, std::string());
local_state->RegisterStringPref(prefs::kHardwareKeyboardLayout,
std::string());
#endif // defined(OS_CHROMEOS)
#if !defined(OS_CHROMEOS)
local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled,
GoogleUpdateSettings::GetCollectStatsConsent());
#endif // !defined(OS_CHROMEOS)
// The number of max sockets per group cannot be greater than the max number
// of sockets per proxy server. We tried using 8, and it can easily
// lead to total browser stalls.
const int proxy_connections_16 =
proxy_connection_trial->AppendGroup("proxy_connections_16",
kProxyConnectionProbability);
const int proxy_connections_64 =
proxy_connection_trial->AppendGroup("proxy_connections_64",
kProxyConnectionProbability);
if (is_first_run) {
#if defined(OS_WIN)
// During first run we read the google_update registry key to find what
// language the user selected when downloading the installer. This
// becomes our default language in the prefs.
// Other platforms obey the system locale.
std::wstring install_lang;
if (GoogleUpdateSettings::GetLanguage(&install_lang)) {
local_state->SetString(prefs::kApplicationLocale,
WideToASCII(install_lang));
}
#endif // defined(OS_WIN)
}
const int proxy_connections_trial_group = proxy_connection_trial->group();
// If the local state file for the current profile doesn't exist and the
// parent profile command line flag is present, then we should inherit some
// local state from the parent profile.
// Checking that the local state file for the current profile doesn't exist
// is the most robust way to determine whether we need to inherit or not
// since the parent profile command line flag can be present even when the
// current profile is not a new one, and in that case we do not want to
// inherit and reset the user's setting.
if (!local_state_file_exists &&
parsed_command_line.HasSwitch(switches::kParentProfile)) {
FilePath parent_profile =
parsed_command_line.GetSwitchValuePath(switches::kParentProfile);
scoped_ptr<PrefService> parent_local_state(
PrefService::CreatePrefService(parent_profile, NULL, false));
parent_local_state->RegisterStringPref(prefs::kApplicationLocale,
std::string());
// Right now, we only inherit the locale setting from the parent profile.
local_state->SetString(
prefs::kApplicationLocale,
parent_local_state->GetString(prefs::kApplicationLocale));
}
if (proxy_connections_trial_group == proxy_connections_16) {
net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(16);
} else if (proxy_connections_trial_group == proxy_connections_32) {
net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(32);
} else if (proxy_connections_trial_group == proxy_connections_64) {
net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(64);
} else {
NOTREACHED();
#if defined(OS_CHROMEOS)
if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
std::string owner_locale = local_state->GetString(prefs::kOwnerLocale);
// Ensure that we start with owner's locale.
if (!owner_locale.empty() &&
local_state->GetString(prefs::kApplicationLocale) != owner_locale &&
!local_state->IsManagedPreference(prefs::kApplicationLocale)) {
local_state->SetString(prefs::kApplicationLocale, owner_locale);
local_state->ScheduleSavePersistentPrefs();
}
}
#endif
return local_state;
}
// 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() {
if (parsed_command_line().HasSwitch(switches::kUseSpdy)) {
std::string spdy_mode =
parsed_command_line().GetSwitchValueASCII(switches::kUseSpdy);
net::HttpNetworkLayer::EnableSpdy(spdy_mode);
} else {
#if !defined(OS_CHROMEOS)
bool is_spdy_trial = false;
const base::FieldTrial::Probability kSpdyDivisor = 100;
base::FieldTrial::Probability npnhttp_probability = 5;
// Windows-specific initialization code for the sandbox broker services. This
// is just a NOP on non-Windows platforms to reduce ifdefs later on.
void InitializeBrokerServices(const MainFunctionParams& parameters,
const CommandLine& parsed_command_line) {
#if defined(OS_WIN)
sandbox::BrokerServices* broker_services =
parameters.sandbox_info_.BrokerServices();
if (broker_services) {
sandbox::InitBrokerServices(broker_services);
if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) {
bool use_winsta = !parsed_command_line.HasSwitch(
switches::kDisableAltWinstation);
// Precreate the desktop and window station used by the renderers.
sandbox::TargetPolicy* policy = broker_services->CreatePolicy();
sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta);
CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result);
policy->Release();
}
}
#endif
}
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial(
"SpdyImpact", kSpdyDivisor, "npn_with_spdy", 2011, 6, 30));
// Initializes the profile, possibly doing some user prompting to pick a
// fallback profile. Returns the newly created profile, or NULL if startup
// should not continue.
Profile* CreateProfile(const MainFunctionParams& parameters,
const FilePath& user_data_dir,
const CommandLine& parsed_command_line) {
Profile* profile;
if (ProfileManager::IsMultipleProfilesEnabled()) {
if (parsed_command_line.HasSwitch(switches::kProfileDirectory)) {
g_browser_process->local_state()->SetString(prefs::kProfileLastUsed,
parsed_command_line.GetSwitchValueASCII(
switches::kProfileDirectory));
}
profile = g_browser_process->profile_manager()->GetLastUsedProfile(
user_data_dir);
} else {
profile = g_browser_process->profile_manager()->GetDefaultProfile(
user_data_dir);
}
// npn with spdy support is the default.
int npn_spdy_grp = trial->kDefaultGroupNumber;
if (profile)
return profile;
// npn with only http support, no spdy.
int npn_http_grp = trial->AppendGroup("npn_with_http", npnhttp_probability);
#if defined(OS_WIN)
// Ideally, we should be able to run w/o access to disk. For now, we
// prompt the user to pick a different user-data-dir and restart chrome
// with the new dir.
// http://code.google.com/p/chromium/issues/detail?id=11510
FilePath new_user_data_dir = UserDataDirDialog::RunUserDataDirDialog(
user_data_dir);
if (!parameters.ui_task && browser_shutdown::delete_resources_on_shutdown) {
// Only delete the resources if we're not running tests. If we're running
// tests the resources need to be reused as many places in the UI cache
// SkBitmaps from the ResourceBundle.
ResourceBundle::CleanupSharedInstance();
}
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);
if (!new_user_data_dir.empty()) {
// Because of the way CommandLine parses, it's sufficient to append a new
// --user-data-dir switch. The last flag of the same name wins.
// TODO(tc): It would be nice to remove the flag we don't want, but that
// sounds risky if we parse differently than CommandLineToArgvW.
CommandLine new_command_line = parameters.command_line_;
new_command_line.AppendSwitchPath(switches::kUserDataDir,
new_user_data_dir);
base::LaunchProcess(new_command_line, base::LaunchOptions(), NULL);
}
#else
// Always enable SPDY on Chrome OS
net::HttpNetworkLayer::EnableSpdy("npn");
#endif // !defined(OS_CHROMEOS)
}
// Setup SPDY CWND Field trial.
const base::FieldTrial::Probability kSpdyCwndDivisor = 100;
const base::FieldTrial::Probability kSpdyCwnd16 = 20; // fixed at 16
const base::FieldTrial::Probability kSpdyCwnd10 = 20; // fixed at 10
const base::FieldTrial::Probability kSpdyCwndMin16 = 20; // no less than 16
const base::FieldTrial::Probability kSpdyCwndMin10 = 20; // no less than 10
// TODO(port): fix this. See comments near the definition of
// user_data_dir. It is better to CHECK-fail here than it is to
// silently exit because of missing code in the above test.
CHECK(profile) << "Cannot get default profile.";
#endif
// After June 30, 2011 builds, it will always be in default group
// (cwndDynamic).
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial(
"SpdyCwnd", kSpdyCwndDivisor, "cwndDynamic", 2011, 6, 30));
return NULL;
}
trial->AppendGroup("cwnd10", kSpdyCwnd10);
trial->AppendGroup("cwnd16", kSpdyCwnd16);
trial->AppendGroup("cwndMin16", kSpdyCwndMin16);
trial->AppendGroup("cwndMin10", kSpdyCwndMin10);
#if defined(OS_WIN)
if (parsed_command_line().HasSwitch(switches::kMaxSpdyConcurrentStreams)) {
int value = 0;
base::StringToInt(parsed_command_line().GetSwitchValueASCII(
switches::kMaxSpdyConcurrentStreams),
&value);
if (value > 0)
net::SpdySession::set_max_concurrent_streams(value);
}
// gfx::Font callbacks
void AdjustUIFont(LOGFONT* logfont) {
l10n_util::AdjustUIFont(logfont);
}
// If --socket-reuse-policy is not specified, run an A/B test for choosing the
// warmest socket.
void BrowserMainParts::WarmConnectionFieldTrial() {
const CommandLine& command_line = parsed_command_line();
if (command_line.HasSwitch(switches::kSocketReusePolicy)) {
std::string socket_reuse_policy_str = command_line.GetSwitchValueASCII(
switches::kSocketReusePolicy);
int policy = -1;
base::StringToInt(socket_reuse_policy_str, &policy);
int GetMinimumFontSize() {
int min_font_size;
base::StringToInt(l10n_util::GetStringUTF16(IDS_MINIMUM_UI_FONT_SIZE),
&min_font_size);
return min_font_size;
}
const int policy_list[] = { 0, 1, 2 };
VLOG(1) << "Setting socket_reuse_policy = " << policy;
SetSocketReusePolicy(policy, policy_list, arraysize(policy_list));
return;
}
#endif
const base::FieldTrial::Probability kWarmSocketDivisor = 100;
const base::FieldTrial::Probability kWarmSocketProbability = 33;
#if defined(TOOLKIT_USES_GTK)
static void GLibLogHandler(const gchar* log_domain,
GLogLevelFlags log_level,
const gchar* message,
gpointer userdata) {
if (!log_domain)
log_domain = "<unknown>";
if (!message)
message = "<no message>";
// After January 30, 2013 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> warmest_socket_trial(
new base::FieldTrial(
"WarmSocketImpact", kWarmSocketDivisor, "last_accessed_socket",
2013, 1, 30));
// Default value is USE_LAST_ACCESSED_SOCKET.
const int last_accessed_socket = warmest_socket_trial->kDefaultGroupNumber;
const int warmest_socket = warmest_socket_trial->AppendGroup(
"warmest_socket", kWarmSocketProbability);
const int warm_socket = warmest_socket_trial->AppendGroup(
"warm_socket", kWarmSocketProbability);
const int warmest_socket_trial_group = warmest_socket_trial->group();
const int policy_list[] = { warmest_socket, warm_socket,
last_accessed_socket };
SetSocketReusePolicy(warmest_socket_trial_group, policy_list,
arraysize(policy_list));
}
// If neither --enable-connect-backup-jobs or --disable-connect-backup-jobs is
// specified, run an A/B test for automatically establishing backup TCP
// connections when a certain timeout value is exceeded.
void BrowserMainParts::ConnectBackupJobsFieldTrial() {
if (parsed_command_line().HasSwitch(switches::kEnableConnectBackupJobs)) {
net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
true);
} else if (parsed_command_line().HasSwitch(
switches::kDisableConnectBackupJobs)) {
net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
false);
if (strstr(message, "Loading IM context type") ||
strstr(message, "wrong ELF class: ELFCLASS64")) {
// http://crbug.com/9643
// Until we have a real 64-bit build or all of these 32-bit package issues
// are sorted out, don't fatal on ELF 32/64-bit mismatch warnings and don't
// spam the user with more than one of them.
static bool alerted = false;
if (!alerted) {
LOG(ERROR) << "Bug 9643: " << log_domain << ": " << message;
alerted = true;
}
} else if (strstr(message, "gtk_widget_size_allocate(): attempt to "
"allocate widget with width") &&
!GTK_CHECK_VERSION(2, 16, 1)) {
// This warning only occurs in obsolete versions of GTK and is harmless.
// http://crbug.com/11133
} else if (strstr(message, "Theme file for default has no") ||
strstr(message, "Theme directory") ||
strstr(message, "theme pixmap")) {
LOG(ERROR) << "GTK theme error: " << message;
} else if (strstr(message, "gtk_drag_dest_leave: assertion")) {
LOG(ERROR) << "Drag destination deleted: http://crbug.com/18557";
} else if (strstr(message, "Out of memory") &&
strstr(log_domain, "<unknown>")) {
LOG(ERROR) << "DBus call timeout or out of memory: "
<< "http://crosbug.com/15496";
} else {
const base::FieldTrial::Probability kConnectBackupJobsDivisor = 100;
// 1% probability.
const base::FieldTrial::Probability kConnectBackupJobsProbability = 1;
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial("ConnnectBackupJobs",
kConnectBackupJobsDivisor, "ConnectBackupJobsEnabled", 2011, 6,
30));
const int connect_backup_jobs_enabled = trial->kDefaultGroupNumber;
trial->AppendGroup("ConnectBackupJobsDisabled",
kConnectBackupJobsProbability);
const int trial_group = trial->group();
net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
trial_group == connect_backup_jobs_enabled);
LOG(DFATAL) << log_domain << ": " << message;
}
}
// Test the impact on subsequent Google searches of getting suggestions from
// www.google.TLD instead of clients1.google.TLD.
void BrowserMainParts::SuggestPrefixFieldTrial() {
const base::FieldTrial::Probability kSuggestPrefixDivisor = 100;
// 50% probability.
const base::FieldTrial::Probability kSuggestPrefixProbability = 50;
// After Jan 1, 2012, it will always be in default group.
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial("SuggestHostPrefix",
kSuggestPrefixDivisor, "Default_Prefix", 2012, 1, 1));
trial->AppendGroup("Www_Prefix", kSuggestPrefixProbability);
// The field trial is detected directly, so we don't need to call anything.
static void SetUpGLibLogHandler() {
// Register GLib-handled assertions to go through our logging system.
const char* kLogDomains[] = { NULL, "Gtk", "Gdk", "GLib", "GLib-GObject" };
for (size_t i = 0; i < arraysize(kLogDomains); i++) {
g_log_set_handler(kLogDomains[i],
static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION |
G_LOG_FLAG_FATAL |
G_LOG_LEVEL_ERROR |
G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_WARNING),
GLibLogHandler,
NULL);
}
}
#endif
// BrowserMainParts: |MainMessageLoopStart()| and related ----------------------
void BrowserMainParts::MainMessageLoopStart() {
PreMainMessageLoopStart();
main_message_loop_.reset(new MessageLoop(MessageLoop::TYPE_UI));
void InitializeToolkit(const MainFunctionParams& parameters) {
// TODO(evan): this function is rather subtle, due to the variety
// of intersecting ifdefs we have. To keep it easy to follow, there
// are no #else branches on any #ifs.
// TODO(viettrungluu): should these really go before setting the thread name?
system_monitor_.reset(new base::SystemMonitor);
hi_res_timer_manager_.reset(new HighResolutionTimerManager);
#if defined(TOOLKIT_USES_GTK)
// We want to call g_thread_init(), but in some codepaths (tests) it
// is possible it has already been called. In older versions of
// GTK, it is an error to call g_thread_init twice; unfortunately,
// the API to tell whether it has been called already was also only
// added in a newer version of GTK! Thankfully, this non-intuitive
// check is actually equivalent and sufficient to work around the
// error.
if (!g_thread_supported())
g_thread_init(NULL);
// Glib type system initialization. Needed at least for gconf,
// used in net/proxy/proxy_config_service_linux.cc. Most likely
// this is superfluous as gtk_init() ought to do this. It's
// definitely harmless, so retained as a reminder of this
// requirement for gconf.
g_type_init();
// We use glib-dbus for geolocation and it's possible other libraries
// (e.g. gnome-keyring) will use it, so initialize its threading here
// as well.
dbus_g_thread_init();
gfx::GtkInitFromCommandLine(parameters.command_line_);
SetUpGLibLogHandler();
#endif
InitializeMainThread();
#if defined(TOOLKIT_GTK)
// It is important for this to happen before the first run dialog, as it
// styles the dialog as well.
gtk_util::InitRCStyles();
#endif
network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
#if defined(TOOLKIT_VIEWS)
// The delegate needs to be set before any UI is created so that windows
// display the correct icon.
if (!views::ViewsDelegate::views_delegate)
views::ViewsDelegate::views_delegate = new ChromeViewsDelegate;
PostMainMessageLoopStart();
Profiling::MainMessageLoopStarted();
}
// TODO(beng): Move to WidgetImpl and implement on Windows too!
if (parameters.command_line_.HasSwitch(switches::kDebugViewsPaint))
views::Widget::SetDebugPaintEnabled(true);
#endif
void BrowserMainParts::InitializeMainThread() {
const char* kThreadName = "CrBrowserMain";
base::PlatformThread::SetName(kThreadName);
main_message_loop().set_thread_name(kThreadName);
#if defined(OS_WIN)
gfx::PlatformFontWin::adjust_font_callback = &AdjustUIFont;
gfx::PlatformFontWin::get_minimum_font_size_callback = &GetMinimumFontSize;
// Register the main thread by instantiating it, but don't call any methods.
main_thread_.reset(new BrowserThread(BrowserThread::UI,
MessageLoop::current()));
// Init common control sex.
INITCOMMONCONTROLSEX config;
config.dwSize = sizeof(config);
config.dwICC = ICC_WIN95_CLASSES;
if (!InitCommonControlsEx(&config))
LOG_GETLASTERROR(FATAL);
#endif
}
// BrowserMainParts: |SetupMetricsAndFieldTrials()| related --------------------
#if defined(OS_CHROMEOS)
// Initializes the metrics service with the configuration for this process,
// returning the created service (guaranteed non-NULL).
MetricsService* BrowserMainParts::InitializeMetrics(
const CommandLine& parsed_command_line,
const PrefService* local_state) {
#if defined(OS_WIN)
if (parsed_command_line.HasSwitch(switches::kChromeFrame))
MetricsLog::set_version_extension("-F");
#elif defined(ARCH_CPU_64_BITS)
MetricsLog::set_version_extension("-64");
#endif // defined(OS_WIN)
// Class is used to login using passed username and password.
// The instance will be deleted upon success or failure.
class StubLogin : public chromeos::LoginStatusConsumer,
public chromeos::LoginUtils::Delegate {
public:
StubLogin(std::string username, std::string password) {
authenticator_ = chromeos::LoginUtils::Get()->CreateAuthenticator(this);
authenticator_.get()->AuthenticateToLogin(
g_browser_process->profile_manager()->GetDefaultProfile(),
username,
password,
std::string(),
std::string());
}
MetricsService* metrics = g_browser_process->metrics_service();
void OnLoginFailure(const chromeos::LoginFailure& error) {
LOG(ERROR) << "Login Failure: " << error.GetErrorString();
delete this;
}
if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly) ||
parsed_command_line.HasSwitch(switches::kEnableBenchmarking)) {
// If we're testing then we don't care what the user preference is, we turn
// on recording, but not reporting, otherwise tests fail.
metrics->StartRecordingOnly();
return metrics;
void OnLoginSuccess(const std::string& username,
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool pending_requests,
bool using_oauth) {
// Will call OnProfilePrepared in the end.
chromeos::LoginUtils::Get()->PrepareProfile(username,
password,
credentials,
pending_requests,
using_oauth,
this);
}
// If the user permits metrics reporting with the checkbox in the
// prefs, we turn on recording. We disable metrics completely for
// non-official builds.
#if defined(GOOGLE_CHROME_BUILD)
#if defined(OS_CHROMEOS)
bool enabled = chromeos::UserCrosSettingsProvider::cached_reporting_enabled();
#else
bool enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled);
#endif // #if defined(OS_CHROMEOS)
if (enabled) {
metrics->Start();
// LoginUtils::Delegate implementation:
virtual void OnProfilePrepared(Profile* profile) {
chromeos::LoginUtils::DoBrowserLaunch(profile, NULL);
delete this;
}
#endif // defined(GOOGLE_CHROME_BUILD)
return metrics;
}
scoped_refptr<chromeos::Authenticator> authenticator_;
};
void BrowserMainParts::SetupFieldTrials(bool metrics_recording_enabled,
bool proxy_policy_is_set) {
// Note: make sure to call ConnectionFieldTrial() before
// ProxyConnectionsFieldTrial().
ConnectionFieldTrial();
SocketTimeoutFieldTrial();
// If a policy is defining the number of active connections this field test
// shoud not be performed.
if (!proxy_policy_is_set)
ProxyConnectionsFieldTrial();
prerender::ConfigurePrefetchAndPrerender(parsed_command_line());
InstantFieldTrial::Activate();
SpdyFieldTrial();
ConnectBackupJobsFieldTrial();
SuggestPrefixFieldTrial();
WarmConnectionFieldTrial();
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line,
Profile* profile) {
if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
std::string first_screen =
parsed_command_line.GetSwitchValueASCII(switches::kLoginScreen);
std::string size_arg =
parsed_command_line.GetSwitchValueASCII(
switches::kLoginScreenSize);
gfx::Size size(0, 0);
// Allow the size of the login window to be set explicitly. If not set,
// default to the entire screen. This is mostly useful for testing.
if (size_arg.size()) {
std::vector<std::string> dimensions;
base::SplitString(size_arg, ',', &dimensions);
if (dimensions.size() == 2) {
int width, height;
if (base::StringToInt(dimensions[0], &width) &&
base::StringToInt(dimensions[1], &height))
size.SetSize(width, height);
}
}
browser::ShowLoginWizard(first_screen, size);
} else if (parsed_command_line.HasSwitch(switches::kLoginUser) &&
parsed_command_line.HasSwitch(switches::kLoginPassword)) {
chromeos::BootTimesLoader::Get()->RecordLoginAttempted();
new StubLogin(
parsed_command_line.GetSwitchValueASCII(switches::kLoginUser),
parsed_command_line.GetSwitchValueASCII(switches::kLoginPassword));
} else {
// We did not log in (we crashed or are debugging), so we need to
// set the user name for sync.
profile->GetProfileSyncService(
chromeos::UserManager::Get()->logged_in_user().email());
}
}
// -----------------------------------------------------------------------------
// TODO(viettrungluu): move more/rest of BrowserMain() into above structure
#else
namespace {
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line,
Profile* profile) {
// Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below.
}
// This function provides some ways to test crash and assertion handling
// behavior of the program.
void HandleTestParameters(const CommandLine& command_line) {
// This parameter causes an assertion.
if (command_line.HasSwitch(switches::kBrowserAssertTest)) {
DCHECK(false);
}
#endif // defined(OS_CHROMEOS)
// This parameter causes a null pointer crash (crash reporter trigger).
if (command_line.HasSwitch(switches::kBrowserCrashTest)) {
int* bad_pointer = NULL;
*bad_pointer = 0;
}
#if defined(OS_MACOSX)
OSStatus KeychainCallback(SecKeychainEvent keychain_event,
SecKeychainCallbackInfo *info, void *context) {
return noErr;
}
#endif
#if defined(OS_CHROMEOS)
// Test loading libcros and exit. We return 0 if the library could be loaded,
// and 1 if it can't be. This is for validation that the library is installed
// and versioned properly for Chrome to find.
if (command_line.HasSwitch(switches::kTestLoadLibcros))
exit(!chromeos::CrosLibrary::Get()->EnsureLoaded());
#endif
}
void RegisterTranslateableItems(void) {
struct {
const char* stock_id;
int resource_id;
} translations[] = {
{ GTK_STOCK_COPY, IDS_COPY },
{ GTK_STOCK_CUT, IDS_CUT },
{ GTK_STOCK_PASTE, IDS_PASTE },
{ GTK_STOCK_DELETE, IDS_DELETE },
{ GTK_STOCK_SELECT_ALL, IDS_SELECT_ALL },
{ NULL, -1 }
}, *trans;
void RunUIMessageLoop(BrowserProcess* browser_process) {
TRACE_EVENT_BEGIN_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
// This should be invoked as close to the start of the browser's
// UI thread message loop as possible to get a stable measurement
// across versions.
RecordBrowserStartupTime();
for (trans = translations; trans->stock_id; trans++) {
GtkStockItem stock_item;
if (gtk_stock_lookup(trans->stock_id, &stock_item)) {
std::string trans_label = gfx::ConvertAcceleratorsFromWindowsStyle(
l10n_util::GetStringUTF8(trans->resource_id));
stock_item.label = g_strdup(trans_label.c_str());
gtk_stock_add(&stock_item, 1);
g_free(stock_item.label);
}
}
}
#endif // defined(OS_CHROMEOS)
// If the UI thread blocks, the whole UI is unresponsive.
// Do not allow disk IO from the UI thread.
base::ThreadRestrictions::SetIOAllowed(false);
void SetSocketReusePolicy(int warmest_socket_trial_group,
const int socket_policy[],
int num_groups) {
const int* result = std::find(socket_policy, socket_policy + num_groups,
warmest_socket_trial_group);
DCHECK_NE(result, socket_policy + num_groups)
<< "Not a valid socket reuse policy group";
net::SetSocketReusePolicy(result - socket_policy);
}
#if defined(TOOLKIT_VIEWS)
views::AcceleratorHandler accelerator_handler;
MessageLoopForUI::current()->Run(&accelerator_handler);
#elif defined(USE_X11)
MessageLoopForUI::current()->Run(NULL);
#elif defined(OS_POSIX)
MessageLoopForUI::current()->Run();
#endif
#if defined(OS_CHROMEOS)
chromeos::BootTimesLoader::Get()->AddLogoutTimeMarker("UIMessageLoopEnded",
true);
#endif
// This code is specific to the Windows-only PreReadExperiment field-trial.
void AddPreReadHistogramTime(const char* name, base::TimeDelta time) {
const base::TimeDelta kMin(base::TimeDelta::FromMilliseconds(1));
const base::TimeDelta kMax(base::TimeDelta::FromHours(1));
static const size_t kBuckets(100);
TRACE_EVENT_END_ETW("BrowserMain:MESSAGE_LOOP", 0, "");
}
// FactoryTimeGet will always return a pointer to the same histogram object,
// keyed on its name. There's no need for us to store it explicitly anywhere.
base::Histogram* counter = base::Histogram::FactoryTimeGet(
name, kMin, kMax, kBuckets, base::Histogram::kUmaTargetedHistogramFlag);
void AddFirstRunNewTabs(BrowserInit* browser_init,
const std::vector<GURL>& new_tabs) {
for (std::vector<GURL>::const_iterator it = new_tabs.begin();
it != new_tabs.end(); ++it) {
if (it->is_valid())
browser_init->AddFirstRunTab(*it);
}
counter->AddTime(time);
}
#if defined(USE_LINUX_BREAKPAD)
class GetLinuxDistroTask : public Task {
public:
explicit GetLinuxDistroTask() {}
bool IsCrashReportingEnabled(const PrefService* local_state) {
// Check whether we should initialize the crash reporter. It may be disabled
// through configuration policy or user preference. It must be disabled for
// Guest mode on Chrome OS in Stable channel.
// The kHeadless environment variable overrides the decision, but only if the
// crash service is under control of the user. It is used by QA testing
// infrastructure to switch on generation of crash reports.
#if defined(OS_CHROMEOS)
bool is_guest_session =
CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession);
bool is_stable_channel =
chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE;
bool breakpad_enabled =
!(is_guest_session && is_stable_channel) &&
chromeos::UserCrosSettingsProvider::cached_reporting_enabled();
if (!breakpad_enabled)
breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
#else
const PrefService::Preference* metrics_reporting_enabled =
local_state->FindPreference(prefs::kMetricsReportingEnabled);
CHECK(metrics_reporting_enabled);
bool breakpad_enabled =
local_state->GetBoolean(prefs::kMetricsReportingEnabled);
if (!breakpad_enabled && metrics_reporting_enabled->IsUserModifiable())
breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
#endif // #if defined(OS_CHROMEOS)
return breakpad_enabled;
}
#endif // #if defined(USE_LINUX_BREAKPAD)
virtual void Run() {
base::GetLinuxDistro(); // Initialize base::linux_distro if needed.
}
} // namespace
DISALLOW_COPY_AND_ASSIGN(GetLinuxDistroTask);
};
#endif // USE_LINUX_BREAKPAD
// BrowserMainParts ------------------------------------------------------------
void InitializeNetworkOptions(const CommandLine& parsed_command_line) {
if (parsed_command_line.HasSwitch(switches::kEnableFileCookies)) {
// Enable cookie storage for file:// URLs. Must do this before the first
// Profile (and therefore the first CookieMonster) is created.
net::CookieMonster::EnableFileScheme();
}
BrowserMainParts::BrowserMainParts(const MainFunctionParams& parameters)
: parameters_(parameters),
parsed_command_line_(parameters.command_line_) {
}
if (parsed_command_line.HasSwitch(switches::kEnableMacCookies))
net::URLRequest::EnableMacCookies();
BrowserMainParts::~BrowserMainParts() {
}
if (parsed_command_line.HasSwitch(switches::kIgnoreCertificateErrors))
net::HttpStreamFactory::set_ignore_certificate_errors(true);
// BrowserMainParts: |EarlyInitialization()| and related -----------------------
if (parsed_command_line.HasSwitch(switches::kHostRules))
net::HttpStreamFactory::SetHostMappingRules(
parsed_command_line.GetSwitchValueASCII(switches::kHostRules));
void BrowserMainParts::EarlyInitialization() {
PreEarlyInitialization();
if (parsed_command_line.HasSwitch(switches::kEnableIPPooling))
net::SpdySessionPool::enable_ip_pooling(true);
if (parsed_command_line().HasSwitch(switches::kEnableBenchmarking))
base::FieldTrial::EnableBenchmarking();
if (parsed_command_line.HasSwitch(switches::kDisableIPPooling))
net::SpdySessionPool::enable_ip_pooling(false);
InitializeSSL();
if (parsed_command_line.HasSwitch(switches::kMaxSpdySessionsPerDomain)) {
int value;
base::StringToInt(parsed_command_line.GetSwitchValueASCII(
switches::kMaxSpdySessionsPerDomain),
&value);
net::SpdySessionPool::set_max_sessions_per_domain(value);
if (parsed_command_line().HasSwitch(switches::kDisableSSLFalseStart))
net::SSLConfigService::DisableFalseStart();
if (parsed_command_line().HasSwitch(switches::kEnableSSLCachedInfo))
net::SSLConfigService::EnableCachedInfo();
if (parsed_command_line().HasSwitch(switches::kEnableOriginBoundCerts))
net::SSLConfigService::EnableOriginBoundCerts();
if (parsed_command_line().HasSwitch(
switches::kEnableDNSCertProvenanceChecking)) {
net::SSLConfigService::EnableDNSCertProvenanceChecking();
}
SetDnsCertProvenanceCheckerFactory(CreateChromeDnsCertProvenanceChecker);
// TODO(abarth): Should this move to InitializeNetworkOptions? This doesn't
// seem dependent on InitializeSSL().
if (parsed_command_line().HasSwitch(switches::kEnableTcpFastOpen))
net::set_tcp_fastopen_enabled(true);
if (parsed_command_line.HasSwitch(switches::kEnableWebSocketOverSpdy)) {
// Enable WebSocket over SPDY.
net::WebSocketJob::set_websocket_over_spdy_enabled(true);
}
PostEarlyInitialization();
}
void InitializeURLRequestThrottlerManager(net::NetLog* net_log) {
net::URLRequestThrottlerManager::GetInstance()->set_enable_thread_checks(
true);
// This will be called after the command-line has been mutated by about:flags
MetricsService* BrowserMainParts::SetupMetricsAndFieldTrials(
const CommandLine& parsed_command_line,
PrefService* local_state) {
// Must initialize metrics after labs have been converted into switches,
// but before field trials are set up (so that client ID is available for
// one-time randomized field trials).
MetricsService* metrics = InitializeMetrics(parsed_command_line, local_state);
// TODO(joi): Passing the NetLog here is temporary; once I switch the
// URLRequestThrottlerManager to be part of the URLRequestContext it will
// come from there. Doing it this way for now (2011/5/12) to try to fail
// fast in case A/B experiment gives unexpected results.
net::URLRequestThrottlerManager::GetInstance()->set_net_log(net_log);
}
// Initialize FieldTrialList to support FieldTrials that use one-time
// randomization. The client ID will be empty if the user has not opted
// to send metrics.
field_trial_list_.reset(new base::FieldTrialList(metrics->GetClientId()));
// Creates key child threads. We need to do this explicitly since
// BrowserThread::PostTask silently deletes a posted task if the target message
// loop isn't created.
void CreateChildThreads(BrowserProcessImpl* process) {
process->db_thread();
process->file_thread();
process->process_launcher_thread();
process->cache_thread();
process->io_thread();
#if defined(OS_CHROMEOS)
process->web_socket_proxy_thread();
#endif
// Create watchdog thread after creating all other threads because it will
// watch the other threads and they must be running.
process->watchdog_thread();
}
SetupFieldTrials(metrics->recording_active(),
local_state->IsManagedPreference(
prefs::kMaxConnectionsPerProxy));
// Returns the new local state object, guaranteed non-NULL.
PrefService* InitializeLocalState(const CommandLine& parsed_command_line,
bool is_first_run) {
FilePath local_state_path;
PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
bool local_state_file_exists = file_util::PathExists(local_state_path);
// Initialize FieldTrialSynchronizer system. This is a singleton and is used
// for posting tasks via NewRunnableMethod. Its deleted when it goes out of
// scope. Even though NewRunnableMethod does AddRef and Release, the object
// will not be deleted after the Task is executed.
field_trial_synchronizer_ = new FieldTrialSynchronizer();
// Load local state. This includes the application locale so we know which
// locale dll to load.
PrefService* local_state = g_browser_process->local_state();
DCHECK(local_state);
return metrics;
}
// TODO(brettw,*): this comment about ResourceBundle was here since
// initial commit. This comment seems unrelated, bit-rotten and
// a candidate for removal.
// Initialize ResourceBundle which handles files loaded from external
// sources. This has to be done before uninstall code path and before prefs
// are registered.
local_state->RegisterStringPref(prefs::kApplicationLocale, std::string());
#if defined(OS_CHROMEOS)
local_state->RegisterStringPref(prefs::kOwnerLocale, std::string());
local_state->RegisterStringPref(prefs::kHardwareKeyboardLayout,
std::string());
#endif // defined(OS_CHROMEOS)
#if !defined(OS_CHROMEOS)
local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled,
GoogleUpdateSettings::GetCollectStatsConsent());
#endif // !defined(OS_CHROMEOS)
// 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 base::FieldTrial::Probability kConnectDivisor = 100;
const base::FieldTrial::Probability kConnectProbability = 1; // 1% prob.
if (is_first_run) {
#if defined(OS_WIN)
// During first run we read the google_update registry key to find what
// language the user selected when downloading the installer. This
// becomes our default language in the prefs.
// Other platforms obey the system locale.
std::wstring install_lang;
if (GoogleUpdateSettings::GetLanguage(&install_lang)) {
local_state->SetString(prefs::kApplicationLocale,
WideToASCII(install_lang));
}
#endif // defined(OS_WIN)
}
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> connect_trial(
new base::FieldTrial(
"ConnCountImpact", kConnectDivisor, "conn_count_6", 2011, 6, 30));
// If the local state file for the current profile doesn't exist and the
// parent profile command line flag is present, then we should inherit some
// local state from the parent profile.
// Checking that the local state file for the current profile doesn't exist
// is the most robust way to determine whether we need to inherit or not
// since the parent profile command line flag can be present even when the
// current profile is not a new one, and in that case we do not want to
// inherit and reset the user's setting.
if (!local_state_file_exists &&
parsed_command_line.HasSwitch(switches::kParentProfile)) {
FilePath parent_profile =
parsed_command_line.GetSwitchValuePath(switches::kParentProfile);
scoped_ptr<PrefService> parent_local_state(
PrefService::CreatePrefService(parent_profile, NULL, false));
parent_local_state->RegisterStringPref(prefs::kApplicationLocale,
std::string());
// Right now, we only inherit the locale setting from the parent profile.
local_state->SetString(
prefs::kApplicationLocale,
parent_local_state->GetString(prefs::kApplicationLocale));
}
// This (6) is the current default value. Having this group declared here
// makes it straightforward to modify |kConnectProbability| such that the same
// probability value will be assigned to all the other groups, while
// preserving the remainder of the of probability space to the default value.
const int connect_6 = connect_trial->kDefaultGroupNumber;
#if defined(OS_CHROMEOS)
if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
std::string owner_locale = local_state->GetString(prefs::kOwnerLocale);
// Ensure that we start with owner's locale.
if (!owner_locale.empty() &&
local_state->GetString(prefs::kApplicationLocale) != owner_locale &&
!local_state->IsManagedPreference(prefs::kApplicationLocale)) {
local_state->SetString(prefs::kApplicationLocale, owner_locale);
local_state->ScheduleSavePersistentPrefs();
}
}
#endif
const int connect_5 = connect_trial->AppendGroup("conn_count_5",
kConnectProbability);
const int connect_7 = connect_trial->AppendGroup("conn_count_7",
kConnectProbability);
const int connect_8 = connect_trial->AppendGroup("conn_count_8",
kConnectProbability);
const int connect_9 = connect_trial->AppendGroup("conn_count_9",
kConnectProbability);
return local_state;
}
const int connect_trial_group = connect_trial->group();
// Windows-specific initialization code for the sandbox broker services. This
// is just a NOP on non-Windows platforms to reduce ifdefs later on.
void InitializeBrokerServices(const MainFunctionParams& parameters,
const CommandLine& parsed_command_line) {
#if defined(OS_WIN)
sandbox::BrokerServices* broker_services =
parameters.sandbox_info_.BrokerServices();
if (broker_services) {
sandbox::InitBrokerServices(broker_services);
if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) {
bool use_winsta = !parsed_command_line.HasSwitch(
switches::kDisableAltWinstation);
// Precreate the desktop and window station used by the renderers.
sandbox::TargetPolicy* policy = broker_services->CreatePolicy();
sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta);
CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result);
policy->Release();
}
if (connect_trial_group == connect_5) {
net::ClientSocketPoolManager::set_max_sockets_per_group(5);
} else if (connect_trial_group == connect_6) {
net::ClientSocketPoolManager::set_max_sockets_per_group(6);
} else if (connect_trial_group == connect_7) {
net::ClientSocketPoolManager::set_max_sockets_per_group(7);
} else if (connect_trial_group == connect_8) {
net::ClientSocketPoolManager::set_max_sockets_per_group(8);
} else if (connect_trial_group == connect_9) {
net::ClientSocketPoolManager::set_max_sockets_per_group(9);
} else {
NOTREACHED();
}
#endif
}
// Initializes the profile, possibly doing some user prompting to pick a
// fallback profile. Returns the newly created profile, or NULL if startup
// should not continue.
Profile* CreateProfile(const MainFunctionParams& parameters,
const FilePath& user_data_dir,
const CommandLine& parsed_command_line) {
Profile* profile;
if (ProfileManager::IsMultipleProfilesEnabled()) {
if (parsed_command_line.HasSwitch(switches::kProfileDirectory)) {
g_browser_process->local_state()->SetString(prefs::kProfileLastUsed,
parsed_command_line.GetSwitchValueASCII(
switches::kProfileDirectory));
}
profile = g_browser_process->profile_manager()->GetLastUsedProfile(
user_data_dir);
} else {
profile = g_browser_process->profile_manager()->GetDefaultProfile(
user_data_dir);
}
// 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_CONNECTION_RESETs, since some servers will kill a socket
// before we time it out. Since these are "unused" sockets, we won't retry the
// connection and instead show an error to the user. So we need to be
// conservative here. We've seen that some servers will close the socket after
// as short as 10 seconds. See http://crbug.com/84313 for more details.
void BrowserMainParts::SocketTimeoutFieldTrial() {
const base::FieldTrial::Probability kIdleSocketTimeoutDivisor = 100;
// 1% probability for all experimental settings.
const base::FieldTrial::Probability kSocketTimeoutProbability = 1;
if (profile)
return profile;
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> socket_timeout_trial(
new base::FieldTrial("IdleSktToImpact", kIdleSocketTimeoutDivisor,
"idle_timeout_10", 2011, 6, 30));
const int socket_timeout_10 = socket_timeout_trial->kDefaultGroupNumber;
#if defined(OS_WIN)
// Ideally, we should be able to run w/o access to disk. For now, we
// prompt the user to pick a different user-data-dir and restart chrome
// with the new dir.
// http://code.google.com/p/chromium/issues/detail?id=11510
FilePath new_user_data_dir = UserDataDirDialog::RunUserDataDirDialog(
user_data_dir);
if (!parameters.ui_task && browser_shutdown::delete_resources_on_shutdown) {
// Only delete the resources if we're not running tests. If we're running
// tests the resources need to be reused as many places in the UI cache
// SkBitmaps from the ResourceBundle.
ResourceBundle::CleanupSharedInstance();
}
const int socket_timeout_5 =
socket_timeout_trial->AppendGroup("idle_timeout_5",
kSocketTimeoutProbability);
const int socket_timeout_20 =
socket_timeout_trial->AppendGroup("idle_timeout_20",
kSocketTimeoutProbability);
if (!new_user_data_dir.empty()) {
// Because of the way CommandLine parses, it's sufficient to append a new
// --user-data-dir switch. The last flag of the same name wins.
// TODO(tc): It would be nice to remove the flag we don't want, but that
// sounds risky if we parse differently than CommandLineToArgvW.
CommandLine new_command_line = parameters.command_line_;
new_command_line.AppendSwitchPath(switches::kUserDataDir,
new_user_data_dir);
base::LaunchProcess(new_command_line, base::LaunchOptions(), NULL);
}
#else
// TODO(port): fix this. See comments near the definition of
// user_data_dir. It is better to CHECK-fail here than it is to
// silently exit because of missing code in the above test.
CHECK(profile) << "Cannot get default profile.";
#endif
const int idle_to_trial_group = socket_timeout_trial->group();
return NULL;
if (idle_to_trial_group == socket_timeout_5) {
net::ClientSocketPool::set_unused_idle_socket_timeout(5);
} else if (idle_to_trial_group == socket_timeout_10) {
net::ClientSocketPool::set_unused_idle_socket_timeout(10);
} else if (idle_to_trial_group == socket_timeout_20) {
net::ClientSocketPool::set_unused_idle_socket_timeout(20);
} else {
NOTREACHED();
}
}
#if defined(OS_WIN)
void BrowserMainParts::ProxyConnectionsFieldTrial() {
const base::FieldTrial::Probability kProxyConnectionsDivisor = 100;
// 25% probability
const base::FieldTrial::Probability kProxyConnectionProbability = 1;
// gfx::Font callbacks
void AdjustUIFont(LOGFONT* logfont) {
l10n_util::AdjustUIFont(logfont);
}
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> proxy_connection_trial(
new base::FieldTrial("ProxyConnectionImpact", kProxyConnectionsDivisor,
"proxy_connections_32", 2011, 6, 30));
int GetMinimumFontSize() {
int min_font_size;
base::StringToInt(l10n_util::GetStringUTF16(IDS_MINIMUM_UI_FONT_SIZE),
&min_font_size);
return min_font_size;
}
// This (32 connections per proxy server) is the current default value.
// Declaring it here allows us to easily re-assign the probability space while
// maintaining that the default group always has the remainder of the "share",
// which allows for cleaner and quicker changes down the line if needed.
const int proxy_connections_32 = proxy_connection_trial->kDefaultGroupNumber;
#endif
// The number of max sockets per group cannot be greater than the max number
// of sockets per proxy server. We tried using 8, and it can easily
// lead to total browser stalls.
const int proxy_connections_16 =
proxy_connection_trial->AppendGroup("proxy_connections_16",
kProxyConnectionProbability);
const int proxy_connections_64 =
proxy_connection_trial->AppendGroup("proxy_connections_64",
kProxyConnectionProbability);
#if defined(TOOLKIT_USES_GTK)
static void GLibLogHandler(const gchar* log_domain,
GLogLevelFlags log_level,
const gchar* message,
gpointer userdata) {
if (!log_domain)
log_domain = "<unknown>";
if (!message)
message = "<no message>";
const int proxy_connections_trial_group = proxy_connection_trial->group();
if (strstr(message, "Loading IM context type") ||
strstr(message, "wrong ELF class: ELFCLASS64")) {
// http://crbug.com/9643
// Until we have a real 64-bit build or all of these 32-bit package issues
// are sorted out, don't fatal on ELF 32/64-bit mismatch warnings and don't
// spam the user with more than one of them.
static bool alerted = false;
if (!alerted) {
LOG(ERROR) << "Bug 9643: " << log_domain << ": " << message;
alerted = true;
}
} else if (strstr(message, "gtk_widget_size_allocate(): attempt to "
"allocate widget with width") &&
!GTK_CHECK_VERSION(2, 16, 1)) {
// This warning only occurs in obsolete versions of GTK and is harmless.
// http://crbug.com/11133
} else if (strstr(message, "Theme file for default has no") ||
strstr(message, "Theme directory") ||
strstr(message, "theme pixmap")) {
LOG(ERROR) << "GTK theme error: " << message;
} else if (strstr(message, "gtk_drag_dest_leave: assertion")) {
LOG(ERROR) << "Drag destination deleted: http://crbug.com/18557";
} else if (strstr(message, "Out of memory") &&
strstr(log_domain, "<unknown>")) {
LOG(ERROR) << "DBus call timeout or out of memory: "
<< "http://crosbug.com/15496";
if (proxy_connections_trial_group == proxy_connections_16) {
net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(16);
} else if (proxy_connections_trial_group == proxy_connections_32) {
net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(32);
} else if (proxy_connections_trial_group == proxy_connections_64) {
net::ClientSocketPoolManager::set_max_sockets_per_proxy_server(64);
} else {
LOG(DFATAL) << log_domain << ": " << message;
}
}
static void SetUpGLibLogHandler() {
// Register GLib-handled assertions to go through our logging system.
const char* kLogDomains[] = { NULL, "Gtk", "Gdk", "GLib", "GLib-GObject" };
for (size_t i = 0; i < arraysize(kLogDomains); i++) {
g_log_set_handler(kLogDomains[i],
static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION |
G_LOG_FLAG_FATAL |
G_LOG_LEVEL_ERROR |
G_LOG_LEVEL_CRITICAL |
G_LOG_LEVEL_WARNING),
GLibLogHandler,
NULL);
NOTREACHED();
}
}
#endif
void InitializeToolkit(const MainFunctionParams& parameters) {
// TODO(evan): this function is rather subtle, due to the variety
// of intersecting ifdefs we have. To keep it easy to follow, there
// are no #else branches on any #ifs.
// 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() {
if (parsed_command_line().HasSwitch(switches::kUseSpdy)) {
std::string spdy_mode =
parsed_command_line().GetSwitchValueASCII(switches::kUseSpdy);
net::HttpNetworkLayer::EnableSpdy(spdy_mode);
} else {
#if !defined(OS_CHROMEOS)
bool is_spdy_trial = false;
const base::FieldTrial::Probability kSpdyDivisor = 100;
base::FieldTrial::Probability npnhttp_probability = 5;
#if defined(TOOLKIT_USES_GTK)
// We want to call g_thread_init(), but in some codepaths (tests) it
// is possible it has already been called. In older versions of
// GTK, it is an error to call g_thread_init twice; unfortunately,
// the API to tell whether it has been called already was also only
// added in a newer version of GTK! Thankfully, this non-intuitive
// check is actually equivalent and sufficient to work around the
// error.
if (!g_thread_supported())
g_thread_init(NULL);
// Glib type system initialization. Needed at least for gconf,
// used in net/proxy/proxy_config_service_linux.cc. Most likely
// this is superfluous as gtk_init() ought to do this. It's
// definitely harmless, so retained as a reminder of this
// requirement for gconf.
g_type_init();
// We use glib-dbus for geolocation and it's possible other libraries
// (e.g. gnome-keyring) will use it, so initialize its threading here
// as well.
dbus_g_thread_init();
gfx::GtkInitFromCommandLine(parameters.command_line_);
SetUpGLibLogHandler();
#endif
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial(
"SpdyImpact", kSpdyDivisor, "npn_with_spdy", 2011, 6, 30));
#if defined(TOOLKIT_GTK)
// It is important for this to happen before the first run dialog, as it
// styles the dialog as well.
gtk_util::InitRCStyles();
#endif
// npn with spdy support is the default.
int npn_spdy_grp = trial->kDefaultGroupNumber;
#if defined(TOOLKIT_VIEWS)
// The delegate needs to be set before any UI is created so that windows
// display the correct icon.
if (!views::ViewsDelegate::views_delegate)
views::ViewsDelegate::views_delegate = new ChromeViewsDelegate;
// npn with only http support, no spdy.
int npn_http_grp = trial->AppendGroup("npn_with_http", npnhttp_probability);
// TODO(beng): Move to WidgetImpl and implement on Windows too!
if (parameters.command_line_.HasSwitch(switches::kDebugViewsPaint))
views::Widget::SetDebugPaintEnabled(true);
#endif
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);
}
#else
// Always enable SPDY on Chrome OS
net::HttpNetworkLayer::EnableSpdy("npn");
#endif // !defined(OS_CHROMEOS)
}
#if defined(OS_WIN)
gfx::PlatformFontWin::adjust_font_callback = &AdjustUIFont;
gfx::PlatformFontWin::get_minimum_font_size_callback = &GetMinimumFontSize;
// Setup SPDY CWND Field trial.
const base::FieldTrial::Probability kSpdyCwndDivisor = 100;
const base::FieldTrial::Probability kSpdyCwnd16 = 20; // fixed at 16
const base::FieldTrial::Probability kSpdyCwnd10 = 20; // fixed at 10
const base::FieldTrial::Probability kSpdyCwndMin16 = 20; // no less than 16
const base::FieldTrial::Probability kSpdyCwndMin10 = 20; // no less than 10
// Init common control sex.
INITCOMMONCONTROLSEX config;
config.dwSize = sizeof(config);
config.dwICC = ICC_WIN95_CLASSES;
if (!InitCommonControlsEx(&config))
LOG_GETLASTERROR(FATAL);
#endif
}
// After June 30, 2011 builds, it will always be in default group
// (cwndDynamic).
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial(
"SpdyCwnd", kSpdyCwndDivisor, "cwndDynamic", 2011, 6, 30));
#if defined(OS_CHROMEOS)
trial->AppendGroup("cwnd10", kSpdyCwnd10);
trial->AppendGroup("cwnd16", kSpdyCwnd16);
trial->AppendGroup("cwndMin16", kSpdyCwndMin16);
trial->AppendGroup("cwndMin10", kSpdyCwndMin10);
// Class is used to login using passed username and password.
// The instance will be deleted upon success or failure.
class StubLogin : public chromeos::LoginStatusConsumer,
public chromeos::LoginUtils::Delegate {
public:
StubLogin(std::string username, std::string password) {
authenticator_ = chromeos::LoginUtils::Get()->CreateAuthenticator(this);
authenticator_.get()->AuthenticateToLogin(
g_browser_process->profile_manager()->GetDefaultProfile(),
username,
password,
std::string(),
std::string());
if (parsed_command_line().HasSwitch(switches::kMaxSpdyConcurrentStreams)) {
int value = 0;
base::StringToInt(parsed_command_line().GetSwitchValueASCII(
switches::kMaxSpdyConcurrentStreams),
&value);
if (value > 0)
net::SpdySession::set_max_concurrent_streams(value);
}
}
void OnLoginFailure(const chromeos::LoginFailure& error) {
LOG(ERROR) << "Login Failure: " << error.GetErrorString();
delete this;
}
// If --socket-reuse-policy is not specified, run an A/B test for choosing the
// warmest socket.
void BrowserMainParts::WarmConnectionFieldTrial() {
const CommandLine& command_line = parsed_command_line();
if (command_line.HasSwitch(switches::kSocketReusePolicy)) {
std::string socket_reuse_policy_str = command_line.GetSwitchValueASCII(
switches::kSocketReusePolicy);
int policy = -1;
base::StringToInt(socket_reuse_policy_str, &policy);
void OnLoginSuccess(const std::string& username,
const std::string& password,
const GaiaAuthConsumer::ClientLoginResult& credentials,
bool pending_requests,
bool using_oauth) {
// Will call OnProfilePrepared in the end.
chromeos::LoginUtils::Get()->PrepareProfile(username,
password,
credentials,
pending_requests,
using_oauth,
this);
const int policy_list[] = { 0, 1, 2 };
VLOG(1) << "Setting socket_reuse_policy = " << policy;
SetSocketReusePolicy(policy, policy_list, arraysize(policy_list));
return;
}
// LoginUtils::Delegate implementation:
virtual void OnProfilePrepared(Profile* profile) {
chromeos::LoginUtils::DoBrowserLaunch(profile, NULL);
delete this;
}
const base::FieldTrial::Probability kWarmSocketDivisor = 100;
const base::FieldTrial::Probability kWarmSocketProbability = 33;
scoped_refptr<chromeos::Authenticator> authenticator_;
};
// After January 30, 2013 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> warmest_socket_trial(
new base::FieldTrial(
"WarmSocketImpact", kWarmSocketDivisor, "last_accessed_socket",
2013, 1, 30));
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line,
Profile* profile) {
if (parsed_command_line.HasSwitch(switches::kLoginManager)) {
std::string first_screen =
parsed_command_line.GetSwitchValueASCII(switches::kLoginScreen);
std::string size_arg =
parsed_command_line.GetSwitchValueASCII(
switches::kLoginScreenSize);
gfx::Size size(0, 0);
// Allow the size of the login window to be set explicitly. If not set,
// default to the entire screen. This is mostly useful for testing.
if (size_arg.size()) {
std::vector<std::string> dimensions;
base::SplitString(size_arg, ',', &dimensions);
if (dimensions.size() == 2) {
int width, height;
if (base::StringToInt(dimensions[0], &width) &&
base::StringToInt(dimensions[1], &height))
size.SetSize(width, height);
}
}
browser::ShowLoginWizard(first_screen, size);
} else if (parsed_command_line.HasSwitch(switches::kLoginUser) &&
parsed_command_line.HasSwitch(switches::kLoginPassword)) {
chromeos::BootTimesLoader::Get()->RecordLoginAttempted();
new StubLogin(
parsed_command_line.GetSwitchValueASCII(switches::kLoginUser),
parsed_command_line.GetSwitchValueASCII(switches::kLoginPassword));
// Default value is USE_LAST_ACCESSED_SOCKET.
const int last_accessed_socket = warmest_socket_trial->kDefaultGroupNumber;
const int warmest_socket = warmest_socket_trial->AppendGroup(
"warmest_socket", kWarmSocketProbability);
const int warm_socket = warmest_socket_trial->AppendGroup(
"warm_socket", kWarmSocketProbability);
const int warmest_socket_trial_group = warmest_socket_trial->group();
const int policy_list[] = { warmest_socket, warm_socket,
last_accessed_socket };
SetSocketReusePolicy(warmest_socket_trial_group, policy_list,
arraysize(policy_list));
}
// If neither --enable-connect-backup-jobs or --disable-connect-backup-jobs is
// specified, run an A/B test for automatically establishing backup TCP
// connections when a certain timeout value is exceeded.
void BrowserMainParts::ConnectBackupJobsFieldTrial() {
if (parsed_command_line().HasSwitch(switches::kEnableConnectBackupJobs)) {
net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
true);
} else if (parsed_command_line().HasSwitch(
switches::kDisableConnectBackupJobs)) {
net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
false);
} else {
// We did not log in (we crashed or are debugging), so we need to
// set the user name for sync.
profile->GetProfileSyncService(
chromeos::UserManager::Get()->logged_in_user().email());
const base::FieldTrial::Probability kConnectBackupJobsDivisor = 100;
// 1% probability.
const base::FieldTrial::Probability kConnectBackupJobsProbability = 1;
// After June 30, 2011 builds, it will always be in default group.
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial("ConnnectBackupJobs",
kConnectBackupJobsDivisor, "ConnectBackupJobsEnabled", 2011, 6,
30));
const int connect_backup_jobs_enabled = trial->kDefaultGroupNumber;
trial->AppendGroup("ConnectBackupJobsDisabled",
kConnectBackupJobsProbability);
const int trial_group = trial->group();
net::internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
trial_group == connect_backup_jobs_enabled);
}
}
#else
void OptionallyRunChromeOSLoginManager(const CommandLine& parsed_command_line,
Profile* profile) {
// Dummy empty function for non-ChromeOS builds to avoid extra ifdefs below.
// Test the impact on subsequent Google searches of getting suggestions from
// www.google.TLD instead of clients1.google.TLD.
void BrowserMainParts::SuggestPrefixFieldTrial() {
const base::FieldTrial::Probability kSuggestPrefixDivisor = 100;
// 50% probability.
const base::FieldTrial::Probability kSuggestPrefixProbability = 50;
// After Jan 1, 2012, it will always be in default group.
scoped_refptr<base::FieldTrial> trial(
new base::FieldTrial("SuggestHostPrefix",
kSuggestPrefixDivisor, "Default_Prefix", 2012, 1, 1));
trial->AppendGroup("Www_Prefix", kSuggestPrefixProbability);
// The field trial is detected directly, so we don't need to call anything.
}
#endif // defined(OS_CHROMEOS)
// BrowserMainParts: |MainMessageLoopStart()| and related ----------------------
#if defined(OS_MACOSX)
OSStatus KeychainCallback(SecKeychainEvent keychain_event,
SecKeychainCallbackInfo *info, void *context) {
return noErr;
}
#endif
void BrowserMainParts::MainMessageLoopStart() {
PreMainMessageLoopStart();
#if defined(OS_CHROMEOS)
void RegisterTranslateableItems(void) {
struct {
const char* stock_id;
int resource_id;
} translations[] = {
{ GTK_STOCK_COPY, IDS_COPY },
{ GTK_STOCK_CUT, IDS_CUT },
{ GTK_STOCK_PASTE, IDS_PASTE },
{ GTK_STOCK_DELETE, IDS_DELETE },
{ GTK_STOCK_SELECT_ALL, IDS_SELECT_ALL },
{ NULL, -1 }
}, *trans;
main_message_loop_.reset(new MessageLoop(MessageLoop::TYPE_UI));
for (trans = translations; trans->stock_id; trans++) {
GtkStockItem stock_item;
if (gtk_stock_lookup(trans->stock_id, &stock_item)) {
std::string trans_label = gfx::ConvertAcceleratorsFromWindowsStyle(
l10n_util::GetStringUTF8(trans->resource_id));
stock_item.label = g_strdup(trans_label.c_str());
gtk_stock_add(&stock_item, 1);
g_free(stock_item.label);
}
}
// TODO(viettrungluu): should these really go before setting the thread name?
system_monitor_.reset(new base::SystemMonitor);
hi_res_timer_manager_.reset(new HighResolutionTimerManager);
InitializeMainThread();
network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
PostMainMessageLoopStart();
Profiling::MainMessageLoopStarted();
}
#endif // defined(OS_CHROMEOS)
void SetSocketReusePolicy(int warmest_socket_trial_group,
const int socket_policy[],
int num_groups) {
const int* result = std::find(socket_policy, socket_policy + num_groups,
warmest_socket_trial_group);
DCHECK_NE(result, socket_policy + num_groups)
<< "Not a valid socket reuse policy group";
net::SetSocketReusePolicy(result - socket_policy);
void BrowserMainParts::InitializeMainThread() {
const char* kThreadName = "CrBrowserMain";
base::PlatformThread::SetName(kThreadName);
main_message_loop().set_thread_name(kThreadName);
// Register the main thread by instantiating it, but don't call any methods.
main_thread_.reset(new BrowserThread(BrowserThread::UI,
MessageLoop::current()));
}
// This code is specific to the Windows-only PreReadExperiment field-trial.
void AddPreReadHistogramTime(const char* name, base::TimeDelta time) {
const base::TimeDelta kMin(base::TimeDelta::FromMilliseconds(1));
const base::TimeDelta kMax(base::TimeDelta::FromHours(1));
static const size_t kBuckets(100);
// BrowserMainParts: |SetupMetricsAndFieldTrials()| related --------------------
// FactoryTimeGet will always return a pointer to the same histogram object,
// keyed on its name. There's no need for us to store it explicitly anywhere.
base::Histogram* counter = base::Histogram::FactoryTimeGet(
name, kMin, kMax, kBuckets, base::Histogram::kUmaTargetedHistogramFlag);
// Initializes the metrics service with the configuration for this process,
// returning the created service (guaranteed non-NULL).
MetricsService* BrowserMainParts::InitializeMetrics(
const CommandLine& parsed_command_line,
const PrefService* local_state) {
#if defined(OS_WIN)
if (parsed_command_line.HasSwitch(switches::kChromeFrame))
MetricsLog::set_version_extension("-F");
#elif defined(ARCH_CPU_64_BITS)
MetricsLog::set_version_extension("-64");
#endif // defined(OS_WIN)
counter->AddTime(time);
}
MetricsService* metrics = g_browser_process->metrics_service();
#if defined(USE_LINUX_BREAKPAD)
bool IsCrashReportingEnabled(const PrefService* local_state) {
// Check whether we should initialize the crash reporter. It may be disabled
// through configuration policy or user preference. It must be disabled for
// Guest mode on Chrome OS in Stable channel.
// The kHeadless environment variable overrides the decision, but only if the
// crash service is under control of the user. It is used by QA testing
// infrastructure to switch on generation of crash reports.
if (parsed_command_line.HasSwitch(switches::kMetricsRecordingOnly) ||
parsed_command_line.HasSwitch(switches::kEnableBenchmarking)) {
// If we're testing then we don't care what the user preference is, we turn
// on recording, but not reporting, otherwise tests fail.
metrics->StartRecordingOnly();
return metrics;
}
// If the user permits metrics reporting with the checkbox in the
// prefs, we turn on recording. We disable metrics completely for
// non-official builds.
#if defined(GOOGLE_CHROME_BUILD)
#if defined(OS_CHROMEOS)
bool is_guest_session =
CommandLine::ForCurrentProcess()->HasSwitch(switches::kGuestSession);
bool is_stable_channel =
chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE;
bool breakpad_enabled =
!(is_guest_session && is_stable_channel) &&
chromeos::UserCrosSettingsProvider::cached_reporting_enabled();
if (!breakpad_enabled)
breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
bool enabled = chromeos::UserCrosSettingsProvider::cached_reporting_enabled();
#else
const PrefService::Preference* metrics_reporting_enabled =
local_state->FindPreference(prefs::kMetricsReportingEnabled);
CHECK(metrics_reporting_enabled);
bool breakpad_enabled =
local_state->GetBoolean(prefs::kMetricsReportingEnabled);
if (!breakpad_enabled && metrics_reporting_enabled->IsUserModifiable())
breakpad_enabled = getenv(env_vars::kHeadless) != NULL;
bool enabled = local_state->GetBoolean(prefs::kMetricsReportingEnabled);
#endif // #if defined(OS_CHROMEOS)
return breakpad_enabled;
if (enabled) {
metrics->Start();
}
#endif // defined(GOOGLE_CHROME_BUILD)
return metrics;
}
#endif // #if defined(USE_LINUX_BREAKPAD)
} // namespace
void BrowserMainParts::SetupFieldTrials(bool metrics_recording_enabled,
bool proxy_policy_is_set) {
// Note: make sure to call ConnectionFieldTrial() before
// ProxyConnectionsFieldTrial().
ConnectionFieldTrial();
SocketTimeoutFieldTrial();
// If a policy is defining the number of active connections this field test
// shoud not be performed.
if (!proxy_policy_is_set)
ProxyConnectionsFieldTrial();
prerender::ConfigurePrefetchAndPrerender(parsed_command_line());
InstantFieldTrial::Activate();
SpdyFieldTrial();
ConnectBackupJobsFieldTrial();
SuggestPrefixFieldTrial();
WarmConnectionFieldTrial();
}
// -----------------------------------------------------------------------------
// TODO(viettrungluu): move more/rest of BrowserMain() into BrowserMainParts.
#if defined(OS_CHROMEOS)
// Allows authenticator to be invoked without adding refcounting. The instances
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment