diff options
author | Francois Doray <fdoray@chromium.org> | 2016-02-23 18:50:30 -0500 |
---|---|---|
committer | Francois Doray <fdoray@chromium.org> | 2016-02-23 23:53:56 +0000 |
commit | 97ae8295dfda25dc394112cb84741df9949a65f9 (patch) | |
tree | 643a6747f9e83fdcda7226039afd4e5166791df0 | |
parent | 489f16983f03efade031d3fec1f4b4ce849052ad (diff) | |
download | chromium_src-97ae8295dfda25dc394112cb84741df9949a65f9.zip chromium_src-97ae8295dfda25dc394112cb84741df9949a65f9.tar.gz chromium_src-97ae8295dfda25dc394112cb84741df9949a65f9.tar.bz2 |
Use a valid /prefetch argument when launching a process.
The /prefetch:# argument that is currently added to the command line of
processes launched with content::StartSandboxedProcess is ignored by
Windows because # doesn't respect the [1, 8] constraint.
This CL ensures that a valid /prefetch:# argument is used for every
process launch (except when the feature is disabled by the PreRead
field trial).
BUG=577698
Review URL: https://codereview.chromium.org/1612663002
Cr-Commit-Position: refs/heads/master@{#373241}
(cherry picked from commit 343068c41c299e65a87d935654f0b81a9935250f)
Conflicts:
chrome/service/DEPS
TBR=gab@chromium.org
Review URL: https://codereview.chromium.org/1727983002 .
Cr-Commit-Position: refs/branch-heads/2623@{#484}
Cr-Branched-From: 92d77538a86529ca35f9220bd3cd512cbea1f086-refs/heads/master@{#369907}
44 files changed, 298 insertions, 47 deletions
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc index 2102ae1..089ca12 100644 --- a/chrome/app/chrome_exe_main_win.cc +++ b/chrome/app/chrome_exe_main_win.cc @@ -17,6 +17,8 @@ #include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/win/windows_version.h" @@ -26,10 +28,12 @@ #include "chrome/browser/policy/policy_path_parser.h" #include "chrome/common/chrome_paths_internal.h" #include "chrome/common/chrome_switches.h" +#include "chrome/installer/util/browser_distribution.h" #include "chrome_elf/chrome_elf_main.h" #include "components/crash/content/app/crash_reporter_client.h" #include "components/crash/content/app/crashpad.h" #include "components/startup_metric_utils/browser/startup_metric_utils.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" #include "third_party/crashpad/crashpad/handler/handler_main.h" @@ -152,15 +156,39 @@ int RunAsCrashpadHandler(const base::CommandLine& command_line) { scoped_ptr<char* []> argv_as_utf8(new char*[argv.size() + 1]); std::vector<std::string> storage; storage.reserve(argv.size()); + + size_t arg_append_index = 0; for (size_t i = 0; i < argv.size(); ++i) { + // Remove arguments starting with '/' as they are not supported by crashpad. + if (!argv[i].empty() && argv[i].front() == L'/') + continue; + storage.push_back(base::UTF16ToUTF8(argv[i])); - argv_as_utf8[i] = &storage[i][0]; + argv_as_utf8[arg_append_index] = &storage[arg_append_index][0]; + ++arg_append_index; } - argv_as_utf8[argv.size()] = nullptr; - return crashpad::HandlerMain(static_cast<int>(argv.size()), + argv_as_utf8[arg_append_index] = nullptr; + + return crashpad::HandlerMain(static_cast<int>(storage.size()), argv_as_utf8.get()); } +// Returns true if |command_line| contains a /prefetch:# argument where # is in +// [1, 8]. +bool HasValidWindowsPrefetchArgument(const base::CommandLine& command_line) { + const base::char16 kPrefetchArgumentPrefix[] = L"/prefetch:"; + + for (const auto& arg : command_line.argv()) { + if (arg.size() == arraysize(kPrefetchArgumentPrefix) && + base::StartsWith(arg, kPrefetchArgumentPrefix, + base::CompareCase::SENSITIVE)) { + return arg[arraysize(kPrefetchArgumentPrefix) - 1] >= L'1' && + arg[arraysize(kPrefetchArgumentPrefix) - 1] <= L'8'; + } + } + return false; +} + } // namespace // This helper is looked up in the browser to retrieve the crash reports. See @@ -183,10 +211,22 @@ int main() { #endif // Initialize the CommandLine singleton from the environment. base::CommandLine::Init(0, nullptr); + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + + const std::string process_type = + command_line->GetSwitchValueASCII(switches::kProcessType); + + startup_metric_utils::InitializePreReadOptions( + BrowserDistribution::GetDistribution()->GetRegistryPath()); - std::string process_type = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kProcessType); + // Confirm that an explicit prefetch profile is used for all process types + // except for the browser process. Any new process type will have to assign + // itself a prefetch id. See kPrefetchArgument* constants in + // content_switches.cc for details. + DCHECK(!startup_metric_utils::GetPreReadOptions().use_prefetch_argument || + process_type.empty() || + HasValidWindowsPrefetchArgument(*command_line)); if (process_type == switches::kCrashpadHandler) return RunAsCrashpadHandler(*base::CommandLine::ForCurrentProcess()); @@ -210,7 +250,7 @@ int main() { if (base::win::GetVersion() >= base::win::VERSION_WIN7) EnableHighDPISupport(); - if (AttemptFastNotify(*base::CommandLine::ForCurrentProcess())) + if (AttemptFastNotify(*command_line)) return 0; // Load and launch the chrome dll. *Everything* happens inside. diff --git a/chrome/app/chrome_watcher_command_line_win.cc b/chrome/app/chrome_watcher_command_line_win.cc index 9c8106b..2f79dbc 100644 --- a/chrome/app/chrome_watcher_command_line_win.cc +++ b/chrome/app/chrome_watcher_command_line_win.cc @@ -15,6 +15,7 @@ #include "base/strings/stringprintf.h" #include "base/win/win_util.h" #include "chrome/common/chrome_switches.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "content/public/common/content_switches.h" namespace { @@ -154,6 +155,12 @@ base::CommandLine GenerateChromeWatcherCommandLine( AppendHandleSwitch(kOnIninitializedEventHandleSwitch, on_initialized_event, &command_line); AppendHandleSwitch(kParentHandleSwitch, parent_process, &command_line); + +#if defined(OS_WIN) + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) + command_line.AppendArg(switches::kPrefetchArgumentWatcher); +#endif // defined(OS_WIN) + return command_line; } diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index f28d301..1c24da1 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc @@ -39,7 +39,6 @@ #include "chrome/common/chrome_result_codes.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/env_vars.h" -#include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/google_update_settings.h" #include "chrome/installer/util/install_util.h" @@ -64,13 +63,11 @@ HMODULE LoadModuleWithDirectory(const base::FilePath& module) { ::SetCurrentDirectoryW(module.DirName().value().c_str()); // Get pre-read options from the PreRead field trial. - startup_metric_utils::InitializePreReadOptions( - BrowserDistribution::GetDistribution()->GetRegistryPath()); const startup_metric_utils::PreReadOptions pre_read_options = startup_metric_utils::GetPreReadOptions(); // Pre-read the binary to warm the memory caches (avoids a lot of random IO). - if (!pre_read_options.no_pre_read) { + if (pre_read_options.pre_read) { base::ThreadPriority previous_priority = base::ThreadPriority::NORMAL; if (pre_read_options.high_priority) { previous_priority = base::PlatformThread::GetCurrentThreadPriority(); diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 3b535ce..a66cec3 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn @@ -163,6 +163,10 @@ source_set("browser") { "//components/ssl_errors", "//components/startup_metric_utils/browser:lib", "//components/startup_metric_utils/browser:message_filter_lib", + + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "//components/startup_metric_utils/common", "//components/strings", "//components/suggestions", "//components/sync_bookmarks", diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 4dff7d2..2a2c668 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -111,6 +111,7 @@ #if defined(OS_WIN) #include "base/win/windows_version.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "ui/views/focus/view_storage.h" #elif defined(OS_MACOSX) #include "chrome/browser/chrome_browser_main_mac.h" @@ -1268,6 +1269,11 @@ void BrowserProcessImpl::RestartBackgroundInstance() { new_cl->AppendSwitch(kSwitchesToAddOnAutorestart[i]); } +#if defined(OS_WIN) + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) + new_cl->AppendArg(switches::kPrefetchArgumentBrowserBackground); +#endif // defined(OS_WIN) + DLOG(WARNING) << "Shutting down current instance of the browser."; chrome::AttemptExit(); diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 75aefe8..512df64 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -583,7 +583,10 @@ void SetupPreReadFieldTrial() { registry_path, base::Bind(&ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial)); - // After startup is complete, update the pre-read group in the registry. The + // Initialize the PreRead options for the current process. + startup_metric_utils::InitializePreReadOptions(registry_path); + + // After startup is complete, update the PreRead group in the registry. The // group written in the registry will be used for the next startup. BrowserThread::PostAfterStartupTask( FROM_HERE, content::BrowserThread::GetBlockingPool(), diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index c3bf71a..21f7f95 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -168,6 +168,7 @@ #include "base/strings/string_tokenizer.h" #include "base/win/windows_version.h" #include "chrome/browser/chrome_browser_main_win.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "sandbox/win/src/sandbox_policy.h" #elif defined(OS_MACOSX) #include "chrome/browser/chrome_browser_main_mac.h" @@ -2690,6 +2691,10 @@ bool ChromeContentBrowserClient::IsWin32kLockdownEnabledForMimeType( return false; } + +bool ChromeContentBrowserClient::ShouldUseWindowsPrefetchArgument() const { + return startup_metric_utils::GetPreReadOptions().use_prefetch_argument; +} #endif // defined(OS_WIN) void ChromeContentBrowserClient::RegisterFrameMojoShellServices( diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 6d88e71..060501a 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -281,6 +281,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient { int sandbox_type) const override; bool IsWin32kLockdownEnabledForMimeType( const std::string& mime_type) const override; + bool ShouldUseWindowsPrefetchArgument() const override; #endif void RegisterFrameMojoShellServices( content::ServiceRegistry* registry, diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 5a16c54..1f5fd54 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -753,8 +753,6 @@ 'service/service_process.h', 'service/service_process_prefs.cc', 'service/service_process_prefs.h', - 'service/service_utility_process_host.cc', - 'service/service_utility_process_host.h', ], 'include_dirs': [ '..', @@ -773,11 +771,16 @@ 'service/cloud_print/print_system_dummy.cc', ], }], - ['OS!="win"', { - 'sources!': [ + ['OS=="win"', { + 'sources': [ 'service/service_utility_process_host.cc', 'service/service_utility_process_host.h', ], + 'deps': [ + # TODO(fdoray): Remove this once the PreRead field trial has + # expired. crbug.com/577698 + '../components/components.gyp:startup_metric_utils_common', + ], }], ], }, diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d21934f..1e31929 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3179,6 +3179,9 @@ '../components/components.gyp:signin_core_browser', '../components/components.gyp:startup_metric_utils_browser', '../components/components.gyp:startup_metric_utils_browser_message_filter', + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + '../components/components.gyp:startup_metric_utils_common', '../components/components.gyp:sync_bookmarks', '../components/components.gyp:sync_driver', '../components/components.gyp:sync_sessions', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index bb4e2c3..87b7387 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -340,6 +340,9 @@ '<(DEPTH)/components/components.gyp:metrics_net', '<(DEPTH)/components/components.gyp:omnibox_common', '<(DEPTH)/components/components.gyp:policy_component_common', + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + '<(DEPTH)/components/components.gyp:startup_metric_utils_common', '<(DEPTH)/components/components.gyp:translate_core_common', '<(DEPTH)/components/components.gyp:variations', '<(DEPTH)/components/components.gyp:version_info', diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi index 757f4d8..e21ccbd 100644 --- a/chrome/chrome_installer_util.gypi +++ b/chrome/chrome_installer_util.gypi @@ -122,6 +122,9 @@ '<(DEPTH)/chrome/chrome_resources.gyp:chrome_strings', '<(DEPTH)/chrome/common_constants.gyp:common_constants', '<(DEPTH)/components/components.gyp:metrics', + # TODO(fdoray): Remove this once the PreRead field trial has + # expired. crbug.com/577698 + '<(DEPTH)/components/components.gyp:startup_metric_utils_common', '<(DEPTH)/components/components.gyp:variations', '<(DEPTH)/courgette/courgette.gyp:courgette_lib', '<(DEPTH)/crypto/crypto.gyp:crypto', diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index fb57a95..015ede6 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn @@ -211,6 +211,14 @@ static_library("common") { sources += rebase_path(gypi_values.chrome_common_service_process_sources, ".", "//chrome") + + if (is_win) { + deps = [ + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "//components/startup_metric_utils/common", + ] + } } } diff --git a/chrome/common/DEPS b/chrome/common/DEPS index ead1d81..52cf585 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS @@ -21,6 +21,9 @@ include_rules = [ "+components/printing/common", "+components/policy/core/common", "+components/signin/core/common", + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "+components/startup_metric_utils/common", "+components/strings/grit", "+components/translate/core/common", "+components/url_formatter", diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 1b9d664..c154752 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -1254,6 +1254,14 @@ const char kForceImmersive[] = "force-immersive"; // This flag is only relevant for Windows currently. const char kNoNetworkProfileWarning[] = "no-network-profile-warning"; +// /prefetch:# arguments for the browser process launched in background mode and +// for the watcher process. Use profiles 5, 6 and 7 as documented on +// kPrefetchArgument* in content_switches.cc. +const char kPrefetchArgumentBrowserBackground[] = "/prefetch:5"; +const char kPrefetchArgumentWatcher[] = "/prefetch:6"; +// /prefetch:7 is used by crashpad, which can't depend on constants defined +// here. See crashpad_win.cc for more details. + // For the DelegateExecute verb handler to launch Chrome in desktop mode on // Windows 8 and higher. Used when relaunching metro Chrome. const char kForceDesktop[] = "force-desktop"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 71aac50..4194ae0 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -360,6 +360,8 @@ extern const char kForceDesktop[]; extern const char kForceImmersive[]; extern const char kHideIcons[]; extern const char kNoNetworkProfileWarning[]; +extern const char kPrefetchArgumentBrowserBackground[]; +extern const char kPrefetchArgumentWatcher[]; extern const char kRelaunchShortcut[]; extern const char kShowIcons[]; extern const char kUninstall[]; diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc index 336c011..cd0724b 100644 --- a/chrome/common/service_process_util.cc +++ b/chrome/common/service_process_util.cc @@ -31,6 +31,10 @@ #include "google_apis/gaia/gaia_switches.h" #include "ui/base/ui_base_switches.h" +#if defined(OS_WIN) +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" +#endif // defined(OS_WIN) + #if !defined(OS_MACOSX) namespace { @@ -160,6 +164,12 @@ scoped_ptr<base::CommandLine> CreateServiceProcessCommandLine() { scoped_ptr<base::CommandLine> command_line(new base::CommandLine(exe_path)); command_line->AppendSwitchASCII(switches::kProcessType, switches::kServiceProcess); + +#if defined(OS_WIN) + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) + command_line->AppendArg(switches::kPrefetchArgumentOther); +#endif // defined(OS_WIN) + static const char* const kSwitchesToCopy[] = { switches::kCloudPrintSetupProxy, switches::kCloudPrintURL, diff --git a/chrome/installer/util/BUILD.gn b/chrome/installer/util/BUILD.gn index 0faa59e..45a8579 100644 --- a/chrome/installer/util/BUILD.gn +++ b/chrome/installer/util/BUILD.gn @@ -109,6 +109,10 @@ static_library("with_no_strings") { ":generate_strings", "//base/third_party/dynamic_annotations", "//components/metrics", + + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "//components/startup_metric_utils/common", "//courgette:courgette_lib", "//crypto", "//third_party/bspatch", diff --git a/chrome/installer/util/DEPS b/chrome/installer/util/DEPS index 448e750..2e7e849 100644 --- a/chrome/installer/util/DEPS +++ b/chrome/installer/util/DEPS @@ -4,5 +4,10 @@ include_rules = [ "+chrome/grit/chromium_strings.h", "+components/metrics", + + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "+components/startup_metric_utils/common", + "+third_party/crashpad", ] diff --git a/chrome/installer/util/auto_launch_util.cc b/chrome/installer/util/auto_launch_util.cc index e61cf76..9fbeab7 100644 --- a/chrome/installer/util/auto_launch_util.cc +++ b/chrome/installer/util/auto_launch_util.cc @@ -21,6 +21,7 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/installer/util/util_constants.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "crypto/sha2.h" namespace { @@ -59,6 +60,9 @@ void EnableBackgroundStartAtLogin() { base::CommandLine cmd_line(application_dir.Append(installer::kChromeExe)); cmd_line.AppendSwitch(switches::kNoStartupWindow); + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) + cmd_line.AppendArg(switches::kPrefetchArgumentBrowserBackground); + base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, GetAutoLaunchKeyName(), cmd_line.GetCommandLineString()); } diff --git a/chrome/service/BUILD.gn b/chrome/service/BUILD.gn index bb741209..a1ef809 100644 --- a/chrome/service/BUILD.gn +++ b/chrome/service/BUILD.gn @@ -71,6 +71,11 @@ static_library("service") { "service_utility_process_host.cc", "service_utility_process_host.h", ] + deps += [ + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "//components/startup_metric_utils/common", + ] } else { sources += [ "cloud_print/print_system_dummy.cc" ] } diff --git a/chrome/service/DEPS b/chrome/service/DEPS index 989d2ce..54a3081 100644 --- a/chrome/service/DEPS +++ b/chrome/service/DEPS @@ -1,5 +1,10 @@ include_rules = [ "+chrome/grit", # For generated headers. + + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "+components/startup_metric_utils/common", + "+components/version_info", "+sandbox/win/src", ] diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc index 3ed91b4..3dad747 100644 --- a/chrome/service/service_utility_process_host.cc +++ b/chrome/service/service_utility_process_host.cc @@ -34,6 +34,10 @@ #include "sandbox/win/src/sandbox_types.h" #include "ui/base/ui_base_switches.h" +#if defined(OS_WIN) +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" +#endif // defined(OS_WIN) + namespace { using content::ChildProcessHost; @@ -225,6 +229,11 @@ bool ServiceUtilityProcessHost::StartProcess(bool no_sandbox) { cmd_line.AppendSwitchASCII(switches::kProcessChannelID, channel_id); cmd_line.AppendSwitch(switches::kLang); +#if defined(OS_WIN) + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) + cmd_line.AppendArg(switches::kPrefetchArgumentOther); +#endif // defined(OS_WIN) + if (Launch(&cmd_line, no_sandbox)) { ReportUmaEvent(SERVICE_UTILITY_STARTED); return true; diff --git a/cloud_print/service/win/chrome_launcher.cc b/cloud_print/service/win/chrome_launcher.cc index 5c9013a..d386342 100644 --- a/cloud_print/service/win/chrome_launcher.cc +++ b/cloud_print/service/win/chrome_launcher.cc @@ -214,6 +214,10 @@ void ChromeLauncher::Run() { cmd.AppendSwitchPath(switches::kUserDataDir, user_data_); cmd.AppendSwitch(switches::kNoServiceAutorun); +#if defined(OS_WIN) + cmd.AppendArg(switches::kPrefetchArgumentOther); +#endif // defined(OS_WIN) + // Optional. cmd.AppendSwitch(switches::kDisableDefaultApps); cmd.AppendSwitch(switches::kDisableExtensions); diff --git a/components/crash.gypi b/components/crash.gypi index 00ee69c..8ef86ad 100644 --- a/components/crash.gypi +++ b/components/crash.gypi @@ -217,6 +217,13 @@ ], 'defines': ['CRASH_IMPLEMENTATION'], 'conditions': [ + ['OS=="win"', { + 'dependencies': [ + # TODO(fdoray): Remove this once the PreRead field trial has + # expired. crbug.com/577698 + '<(DEPTH)/components/components.gyp:startup_metric_utils_common', + ], + }], ['OS=="mac" or OS=="win"', { 'dependencies': [ '../third_party/crashpad/crashpad/client/client.gyp:crashpad_client', diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn index 52140ce..3def677 100644 --- a/components/crash/content/app/BUILD.gn +++ b/components/crash/content/app/BUILD.gn @@ -49,6 +49,13 @@ source_set("app") { ] deps += [ ":lib" ] + if (is_win) { + deps += [ + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "//components/startup_metric_utils/common", + ] + } if (is_mac || is_win) { deps += [ "//third_party/crashpad/crashpad/client" ] } diff --git a/components/crash/content/app/DEPS b/components/crash/content/app/DEPS index 80bc21a..01c710b 100644 --- a/components/crash/content/app/DEPS +++ b/components/crash/content/app/DEPS @@ -3,6 +3,11 @@ include_rules = [ "+content/public/common/content_descriptors.h", "+content/public/common/result_codes.h", + + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "+components/startup_metric_utils/common/pre_read_field_trial_utils_win.h", + "+third_party/crashpad", "+third_party/kasko", "+third_party/lss/linux_syscall_support.h", diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc index 1c241ca..95e53e2 100644 --- a/components/crash/content/app/crashpad_win.cc +++ b/components/crash/content/app/crashpad_win.cc @@ -16,6 +16,7 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/crash/content/app/crash_reporter_client.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "third_party/crashpad/crashpad/client/crashpad_client.h" #include "third_party/crashpad/crashpad/client/crashpad_info.h" #include "third_party/crashpad/crashpad/client/simulate_crash_win.h" @@ -75,6 +76,13 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client, exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe")); } else { arguments.push_back("--type=crashpad-handler"); + + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) { + // The prefetch argument added here has to be documented in + // chrome_switches.cc, below the kPrefetchArgument* constants. A + // constant can't be used here because crashpad can't depend on Chrome. + arguments.push_back("/prefetch:7"); + } } // TODO(scottmg): See https://crashpad.chromium.org/bug/23. diff --git a/components/nacl.gyp b/components/nacl.gyp index a9ed69c..2fd7aba 100644 --- a/components/nacl.gyp +++ b/components/nacl.gyp @@ -139,6 +139,13 @@ '../sandbox/sandbox.gyp:sandbox_services', ] }], + ['OS=="win"', { + 'dependencies': [ + # TODO(fdoray): Remove this once the PreRead field trial has + # expired. crbug.com/577698 + '../components/components.gyp:startup_metric_utils_common', + ] + }], ], }, { diff --git a/components/nacl/browser/BUILD.gn b/components/nacl/browser/BUILD.gn index 63c2c9d..9b247f4 100644 --- a/components/nacl/browser/BUILD.gn +++ b/components/nacl/browser/BUILD.gn @@ -63,6 +63,14 @@ source_set("browser") { data_deps += [ "//components/nacl/loader:helper_nonsfi" ] } + if (is_win) { + deps += [ + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "//components/startup_metric_utils/common", + ] + } + if (is_win && current_cpu == "x86") { data_deps += [ "//components/nacl/broker:nacl64" ] } diff --git a/components/nacl/browser/DEPS b/components/nacl/browser/DEPS index efbdb131..2e1a96b 100644 --- a/components/nacl/browser/DEPS +++ b/components/nacl/browser/DEPS @@ -1,4 +1,7 @@ include_rules = [ + # TODO(fdoray): Remove this once the PreRead field trial has expired. + # crbug.com/577698 + "+components/startup_metric_utils/common", "+components/url_formatter", "+content/public/browser", "+content/public/test", diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc index aa4f4c5..2ade0f7 100644 --- a/components/nacl/browser/nacl_process_host.cc +++ b/components/nacl/browser/nacl_process_host.cc @@ -76,6 +76,7 @@ #include "base/win/scoped_handle.h" #include "components/nacl/browser/nacl_broker_service_win.h" #include "components/nacl/common/nacl_debug_exception_handler_win.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "content/public/common/sandbox_init.h" #endif @@ -625,7 +626,12 @@ bool NaClProcessHost::LaunchSelLdr() { if (NaClBrowser::GetDelegate()->DialogsAreSuppressed()) cmd_line->AppendSwitch(switches::kNoErrorDialogs); - // On Windows we might need to start the broker process to launch a new loader +#if defined(OS_WIN) + if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) + cmd_line->AppendArg(switches::kPrefetchArgumentOther); +#endif // defined(OS_WIN) + +// On Windows we might need to start the broker process to launch a new loader #if defined(OS_WIN) if (RunningOnWOW64()) { if (!NaClBrokerService::GetInstance()->LaunchLoader( diff --git a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc index a75a81c..dbb32bf 100644 --- a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc +++ b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc @@ -25,12 +25,16 @@ const char kPreReadFieldTrialName[] = "PreRead"; // annotated with the pre-read group that is actually used during this startup. const char kPreReadSyntheticFieldTrialName[] = "SyntheticPreRead"; -// Variation names for the PreRead field trial. +// Variation names for the PreRead field trial. All variations change the +// default behavior, i.e. the default is the inverse of the variation. Thus, +// variations that cancel something that is done by default have a negative +// name. const base::char16 kNoPreReadVariationName[] = L"NoPreRead"; const base::char16 kHighPriorityVariationName[] = L"HighPriority"; const base::char16 kOnlyIfColdVariationName[] = L"OnlyIfCold"; const base::char16 kPrefetchVirtualMemoryVariationName[] = L"PrefetchVirtualMemory"; +const base::char16 kNoPrefetchArgumentVariationName[] = L"NoPrefetchArgument"; // Registry key in which the PreRead field trial group is stored. const base::char16 kPreReadFieldTrialRegistryKey[] = L"\\PreReadFieldTrial"; @@ -45,6 +49,12 @@ base::string16 GetPreReadRegistryPath( return product_registry_path + kPreReadFieldTrialRegistryKey; } +// Returns true if |key| has a value named |name| which is not zero. +bool ReadBool(const base::win::RegKey& key, const base::char16* name) { + DWORD value = 0; + return key.ReadValueDW(name, &value) == ERROR_SUCCESS && value != 0; +} + } // namespace void InitializePreReadOptions(const base::string16& product_registry_path) { @@ -57,27 +67,13 @@ void InitializePreReadOptions(const base::string16& product_registry_path) { KEY_QUERY_VALUE); // Set the PreRead field trial's options. - struct { - const base::char16* name; - bool* option; - } const variations_mappings[] = { - {kNoPreReadVariationName, &g_pre_read_options.no_pre_read}, - {kHighPriorityVariationName, &g_pre_read_options.high_priority}, - {kOnlyIfColdVariationName, &g_pre_read_options.only_if_cold}, - {kPrefetchVirtualMemoryVariationName, - &g_pre_read_options.prefetch_virtual_memory}, - }; - - for (const auto& mapping : variations_mappings) { - // Set the option variable to true if the corresponding value is found in - // the registry. Set to false otherwise (default behavior). - DWORD value = 0; - if (key.ReadValueDW(mapping.name, &value) == ERROR_SUCCESS) { - DCHECK_EQ(1U, value); - DCHECK(!*mapping.option); - *mapping.option = true; - } - } + g_pre_read_options.pre_read = !ReadBool(key, kNoPreReadVariationName); + g_pre_read_options.high_priority = ReadBool(key, kHighPriorityVariationName); + g_pre_read_options.only_if_cold = ReadBool(key, kOnlyIfColdVariationName); + g_pre_read_options.prefetch_virtual_memory = + ReadBool(key, kPrefetchVirtualMemoryVariationName); + g_pre_read_options.use_prefetch_argument = + !ReadBool(key, kNoPrefetchArgumentVariationName); } PreReadOptions GetPreReadOptions() { diff --git a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h index cacf4b3..a2aaf4a 100644 --- a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h +++ b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h @@ -21,8 +21,8 @@ using RegisterPreReadSyntheticFieldTrialCallback = // The options controlled by the PreRead field trial. struct PreReadOptions { - // No explicit DLL pre-reading. - bool no_pre_read; + // Pre-read DLLs explicitly. + bool pre_read; // Pre-read DLLs with a high thread priority. bool high_priority; @@ -32,6 +32,9 @@ struct PreReadOptions { // Pre-read DLLs using the ::PrefetchVirtualMemory function, if available. bool prefetch_virtual_memory; + + // Use a /prefetch argument when launching a process. + bool use_prefetch_argument; }; // Initializes DLL pre-reading options from the registry. diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index ad9cafe..b3bd310 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -1030,6 +1030,11 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) { cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess); cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); +#if defined(OS_WIN) + if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument()) + cmd_line->AppendArg(switches::kPrefetchArgumentGpu); +#endif // defined(OS_WIN) + if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED) cmd_line->AppendSwitch(switches::kDisableGpuSandbox); diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc index 9ede7a2..cb14fa7 100644 --- a/content/browser/plugin_process_host.cc +++ b/content/browser/plugin_process_host.cc @@ -209,6 +209,11 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) { cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kPluginProcess); cmd_line->AppendSwitchPath(switches::kPluginPath, info.path); +#if defined(OS_WIN) + if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument()) + cmd_line->AppendArg(switches::kPrefetchArgumentOther); +#endif // defined(OS_WIN) + // Propagate the following switches to the plugin command line (along with // any associated values) if present in the browser command line static const char* const kSwitchNames[] = { diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc index e17b694..3523fc1 100644 --- a/content/browser/ppapi_plugin_process_host.cc +++ b/content/browser/ppapi_plugin_process_host.cc @@ -373,6 +373,13 @@ bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) { : switches::kPpapiPluginProcess); cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); +#if defined(OS_WIN) + if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument()) { + cmd_line->AppendArg(is_broker_ ? switches::kPrefetchArgumentPpapiBroker + : switches::kPrefetchArgumentPpapi); + } +#endif // defined(OS_WIN) + // These switches are forwarded to both plugin and broker pocesses. static const char* kCommonForwardSwitches[] = { switches::kVModule diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index bfba388..667dc22 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -1291,6 +1291,11 @@ void RenderProcessHostImpl::AppendRendererCommandLine( command_line->AppendSwitchASCII(switches::kProcessType, switches::kRendererProcess); +#if defined(OS_WIN) + if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument()) + command_line->AppendArg(switches::kPrefetchArgumentRenderer); +#endif // defined(OS_WIN) + // Now send any options from our own command line we want to propagate. const base::CommandLine& browser_command_line = *base::CommandLine::ForCurrentProcess(); diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc index db67d60..42c31bd 100644 --- a/content/browser/utility_process_host_impl.cc +++ b/content/browser/utility_process_host_impl.cc @@ -286,6 +286,11 @@ bool UtilityProcessHostImpl::StartProcess() { std::string locale = GetContentClient()->browser()->GetApplicationLocale(); cmd_line->AppendSwitchASCII(switches::kLang, locale); +#if defined(OS_WIN) + if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument()) + cmd_line->AppendArg(switches::kPrefetchArgumentOther); +#endif // defined(OS_WIN) + if (no_sandbox_) cmd_line->AppendSwitch(switches::kNoSandbox); diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc index 5230738..92a5a24 100644 --- a/content/common/sandbox_win.cc +++ b/content/common/sandbox_win.cc @@ -681,11 +681,6 @@ base::Process StartSandboxedProcess( ProcessDebugFlags(cmd_line); - // Prefetch hints on windows: - // Using a different prefetch profile per process type will allow Windows - // to create separate pretetch settings for browser, renderer etc. - cmd_line->AppendArg(base::StringPrintf("/prefetch:%d", base::Hash(type_str))); - if ((!delegate->ShouldSandbox()) || browser_command_line.HasSwitch(switches::kNoSandbox) || cmd_line->HasSwitch(switches::kNoSandbox)) { diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 121f7c2..3f6d970 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc @@ -418,7 +418,11 @@ bool ContentBrowserClient::IsWin32kLockdownEnabledForMimeType( // is enabled by default in Chrome. See crbug.com/523278. return false; } -#endif + +bool ContentBrowserClient::ShouldUseWindowsPrefetchArgument() const { + return true; +} +#endif // defined(OS_WIN) #if defined(VIDEO_HOLE) ExternalVideoSurfaceContainer* diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index b19adfb..5ecc56e 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -756,6 +756,10 @@ class CONTENT_EXPORT ContentBrowserClient { // a process hosting a plugin with the specified |mime_type|. virtual bool IsWin32kLockdownEnabledForMimeType( const std::string& mime_type) const; + + // Returns true if processes should be launched with a /prefetch:# argument. + // See the kPrefetchArgument* constants in content_switches.cc for details. + virtual bool ShouldUseWindowsPrefetchArgument() const; #endif #if defined(VIDEO_HOLE) diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 1fe03b0..094ecf1 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -968,6 +968,30 @@ const char kDisableCoreAnimationPlugins[] = #endif #if defined(OS_WIN) +// /prefetch:# arguments to use when launching various process types. It has +// been observed that when file reads are consistent for 3 process launches with +// the same /prefetch:# argument, the Windows prefetcher starts issuing reads in +// batch at process launch. Because reads depend on the process type, the +// prefetcher wouldn't be able to observe consistent reads if no /prefetch:# +// arguments were used. Note that the browser process has no /prefetch:# +// argument; as such all other processes must have one in order to avoid +// polluting its profile. Note: # must always be in [1, 8]; otherwise it is +// ignored by the Windows prefetcher. +const char kPrefetchArgumentRenderer[] = "/prefetch:1"; +const char kPrefetchArgumentGpu[] = "/prefetch:2"; +const char kPrefetchArgumentPpapi[] = "/prefetch:3"; +const char kPrefetchArgumentPpapiBroker[] = "/prefetch:4"; +// /prefetch:5, /prefetch:6 and /prefetch:7 are reserved for content embedders +// and are not to be used by content itself. + +// /prefetch:# argument shared by all process types that don't have their own. +// It is likely that the prefetcher won't work for these process types as it +// won't be able to observe consistent file reads across launches. However, +// having a valid prefetch argument for these process types is required to +// prevent them from interfering with the prefetch profile of the browser +// process. +const char kPrefetchArgumentOther[] = "/prefetch:8"; + // Device scale factor passed to certain processes like renderers, etc. const char kDeviceScaleFactor[] = "device-scale-factor"; diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 1174c61..f45e539 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -291,6 +291,11 @@ extern const char kDisableThreadedEventHandlingMac[]; #endif #if defined(OS_WIN) +CONTENT_EXPORT extern const char kPrefetchArgumentRenderer[]; +CONTENT_EXPORT extern const char kPrefetchArgumentGpu[]; +CONTENT_EXPORT extern const char kPrefetchArgumentPpapi[]; +CONTENT_EXPORT extern const char kPrefetchArgumentPpapiBroker[]; +CONTENT_EXPORT extern const char kPrefetchArgumentOther[]; // This switch contains the device scale factor passed to certain processes // like renderers, etc. CONTENT_EXPORT extern const char kDeviceScaleFactor[]; |