Chromium Code Reviews| Index: chrome/browser/first_run/first_run_win.cc |
| diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc |
| index 077a1cfaacd0cc76cb4d4208bcfd41fc8c744d10..7e86c32c85252e9b728325310ca9cd789ab7e299 100644 |
| --- a/chrome/browser/first_run/first_run_win.cc |
| +++ b/chrome/browser/first_run/first_run_win.cc |
| @@ -4,6 +4,7 @@ |
| #include "chrome/browser/first_run/first_run.h" |
| +#include <shellapi.h> |
| #include <shlobj.h> |
| #include <windows.h> |
| @@ -15,6 +16,7 @@ |
| #include "base/string_split.h" |
| #include "base/stringprintf.h" |
| #include "base/utf_string_conversions.h" |
| +#include "base/win/metro.h" |
| #include "base/win/object_watcher.h" |
| #include "base/win/windows_version.h" |
| #include "chrome/browser/browser_process.h" |
| @@ -52,11 +54,10 @@ |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/layout.h" |
| #include "ui/base/ui_base_switches.h" |
| +#include "ui/base/win/shell.h" |
| namespace { |
| -const char kEULASentinelFile[] = "EULA Accepted"; |
| - |
| // Helper class that performs delayed first-run tasks that need more of the |
| // chrome infrastructure to be up and running before they can be attempted. |
| class FirstRunDelayedTasks : public content::NotificationObserver { |
| @@ -144,33 +145,50 @@ void PlatformSetup(Profile* profile) { |
| CreateChromeQuickLaunchShortcut(); |
| } |
| -// Launches the setup exe with the given parameter/value on the command-line, |
| -// waits for its termination, returns its exit code in |*ret_code|, and |
| -// returns true if the exit code is valid. |
| -bool LaunchSetupWithParam(const std::string& param, |
| - const FilePath::StringType& value, |
| - int* ret_code) { |
| - FilePath exe_path; |
| - if (!PathService::Get(base::DIR_MODULE, &exe_path)) |
| +// Launches the setup exe with the given parameter/value on the command-line. |
| +// For non-metro Windows, it waits for its termination, returns its exit code |
| +// in |*ret_code|, and returns true if the exit code is valid. |
| +// For metro Windows, it launches setup via ShellExecuteEx and returns in order |
| +// to bounce the user back to the desktop, then returns immediately. |
| +bool LaunchSetupForEula(const FilePath::StringType& value, int* ret_code) { |
| + FilePath exe_dir; |
| + if (!PathService::Get(base::DIR_MODULE, &exe_dir)) |
| return false; |
| - exe_path = exe_path.Append(installer::kInstallerDir); |
| - exe_path = exe_path.Append(installer::kSetupExe); |
| + exe_dir = exe_dir.Append(installer::kInstallerDir); |
| + FilePath exe_path = exe_dir.Append(installer::kSetupExe); |
| base::ProcessHandle ph; |
| - CommandLine cl(exe_path); |
| - cl.AppendSwitchNative(param, value); |
| + |
| + CommandLine cl(CommandLine::NO_PROGRAM); |
| + cl.AppendSwitchNative(installer::switches::kShowEula, value); |
| CommandLine* browser_command_line = CommandLine::ForCurrentProcess(); |
| if (browser_command_line->HasSwitch(switches::kChromeFrame)) { |
| cl.AppendSwitch(switches::kChromeFrame); |
| } |
| - // TODO(evan): should this use options.wait = true? |
| - if (!base::LaunchProcess(cl, base::LaunchOptions(), &ph)) |
| - return false; |
| - DWORD wr = ::WaitForSingleObject(ph, INFINITE); |
| - if (wr != WAIT_OBJECT_0) |
| + if (base::win::IsMetroProcess()) { |
| + cl.AppendSwitch(installer::switches::kShowEulaForMetro); |
| + |
| + // This obscure use of the 'log usage' mask for windows 8 is documented |
| + // here http://goo.gl/HBOe9. It causes the desktop process to receive |
|
grt (UTC plus 2)
2012/09/20 15:58:31
please link to the current version of the MS doc r
robertshield
2012/09/21 01:24:43
Done.
|
| + // focus. Pass SEE_MASK_FLAG_NO_UI to avoid hangs if an error occurs since |
| + // the UI can't be shown from a metro process. |
| + ui::win::OpenAnyViaShell(exe_path.value(), |
| + exe_dir.value(), |
| + cl.GetCommandLineString(), |
| + SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_FLAG_NO_UI); |
| return false; |
| - return (TRUE == ::GetExitCodeProcess(ph, reinterpret_cast<DWORD*>(ret_code))); |
| + } else { |
| + base::LaunchOptions launch_options; |
| + launch_options.wait = true; |
| + CommandLine setup_path(exe_path); |
| + setup_path.AppendArguments(cl, false); |
| + |
| + if (!base::LaunchProcess(setup_path, launch_options, &ph)) |
| + return false; |
| + return ( |
| + TRUE == ::GetExitCodeProcess(ph, reinterpret_cast<DWORD*>(ret_code))); |
|
grt (UTC plus 2)
2012/09/20 15:58:31
1. please COMPILE_ASSERT(sizeof(*ret_code) == size
robertshield
2012/09/21 01:24:43
Done.
|
| + } |
| } |
| // Populates |path| with the path to |file| in the sentinel directory. This is |
| @@ -190,7 +208,7 @@ bool GetSentinelFilePath(const char* file, FilePath* path) { |
| } |
| bool GetEULASentinelFilePath(FilePath* path) { |
| - return GetSentinelFilePath(kEULASentinelFile, path); |
| + return GetSentinelFilePath(installer::kEULASentinelFile, path); |
| } |
| // Returns true if the EULA is required but has not been accepted by this user. |
| @@ -234,7 +252,10 @@ bool CreateEULASentinel() { |
| return file_util::WriteFile(eula_sentinel, "", 0) != -1; |
| } |
| -void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { |
| +// Shows the EULA dialog if required. Returns true if the EULA is accepted, |
| +// returns false if the EULA has not been accepted, in which case the browser |
| +// should exit. |
| +bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { |
| if (IsEULANotAccepted(install_prefs)) { |
| // Show the post-installation EULA. This is done by setup.exe and the |
| // result determines if we continue or not. We wait here until the user |
| @@ -245,14 +266,14 @@ void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { |
| FilePath inner_html; |
| if (WriteEULAtoTempFile(&inner_html)) { |
| int retcode = 0; |
| - if (!LaunchSetupWithParam(installer::switches::kShowEula, |
| - inner_html.value(), &retcode) || |
| + if (!LaunchSetupForEula(inner_html.value(), &retcode) || |
| (retcode != installer::EULA_ACCEPTED && |
| retcode != installer::EULA_ACCEPTED_OPT_IN)) { |
| - LOG(WARNING) << "EULA rejected. Fast exit."; |
| - ::ExitProcess(1); |
| + LOG(WARNING) << "EULA flow requires fast exit."; |
| + return false; |
| } |
| CreateEULASentinel(); |
| + |
| if (retcode == installer::EULA_ACCEPTED) { |
| VLOG(1) << "EULA : no collection"; |
| GoogleUpdateSettings::SetCollectStatsConsent(false); |
| @@ -262,6 +283,7 @@ void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { |
| } |
| } |
| } |
| + return true; |
| } |
| // Installs a task to do an extensions update check once the extensions system |
| @@ -590,23 +612,26 @@ FilePath MasterPrefsPath() { |
| return master_prefs.AppendASCII(installer::kDefaultMasterPrefs); |
| } |
| -bool ProcessMasterPreferences(const FilePath& user_data_dir, |
| - MasterPrefs* out_prefs) { |
| +ProcessMasterPreferencesResult ProcessMasterPreferences( |
| + const FilePath& user_data_dir, |
| + MasterPrefs* out_prefs) { |
| DCHECK(!user_data_dir.empty()); |
| FilePath master_prefs_path; |
| scoped_ptr<installer::MasterPreferences> |
| install_prefs(internal::LoadMasterPrefs(&master_prefs_path)); |
| if (!install_prefs.get()) |
| - return true; |
| + return SHOW_FIRST_RUN; |
| out_prefs->new_tabs = install_prefs->GetFirstRunTabs(); |
| internal::SetRLZPref(out_prefs, install_prefs.get()); |
| - ShowPostInstallEULAIfNeeded(install_prefs.get()); |
| + |
| + if (!ShowPostInstallEULAIfNeeded(install_prefs.get())) |
| + return EULA_EXIT_NOW; |
| if (!internal::CopyPrefFile(user_data_dir, master_prefs_path)) |
| - return true; |
| + return SHOW_FIRST_RUN; |
| DoDelayedInstallExtensionsIfNeeded(install_prefs.get()); |
| @@ -618,19 +643,19 @@ bool ProcessMasterPreferences(const FilePath& user_data_dir, |
| // Note we are skipping all other master preferences if skip-first-run-ui |
| // is *not* specified. (That is, we continue only if skipping first run ui.) |
| if (!internal::SkipFirstRunUI(install_prefs.get())) |
| - return true; |
| + return SHOW_FIRST_RUN; |
| // We need to be able to create the first run sentinel or else we cannot |
| // proceed because ImportSettings will launch the importer process which |
| // would end up here if the sentinel is not present. |
| if (!CreateSentinel()) |
| - return false; |
| + return SKIP_FIRST_RUN; |
| internal::SetShowWelcomePagePrefIfNeeded(install_prefs.get()); |
| internal::SetImportPreferencesAndLaunchImport(out_prefs, install_prefs.get()); |
| internal::SetDefaultBrowser(install_prefs.get()); |
| - return false; |
| + return SKIP_FIRST_RUN; |
| } |
| } // namespace first_run |