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..fbd92bc10deb3388779a0d1f4a4d685a8d06236d 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,53 +145,61 @@ 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) |
- return false; |
- return (TRUE == ::GetExitCodeProcess(ph, reinterpret_cast<DWORD*>(ret_code))); |
-} |
- |
-// Populates |path| with the path to |file| in the sentinel directory. This is |
-// the application directory for user-level installs, and the default user data |
-// dir for system-level installs. Returns false on error. |
-bool GetSentinelFilePath(const char* file, FilePath* path) { |
- FilePath exe_path; |
- if (!PathService::Get(base::DIR_EXE, &exe_path)) |
- return false; |
- if (InstallUtil::IsPerUserInstall(exe_path.value().c_str())) |
- *path = exe_path; |
- else if (!PathService::Get(chrome::DIR_USER_DATA, path)) |
+ if (base::win::IsMetroProcess()) { |
+ cl.AppendSwitch(installer::switches::kShowEulaForMetro); |
+ |
+ // This obscure use of the 'log usage' mask for windows 8 is documented here |
+ // http://go.microsoft.com/fwlink/?LinkID=243079. It causes the desktop |
+ // process to receive 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; |
+ } else { |
+ base::LaunchOptions launch_options; |
+ launch_options.wait = true; |
+ CommandLine setup_path(exe_path); |
+ setup_path.AppendArguments(cl, false); |
+ |
+ DWORD exit_code = 0; |
+ if (!base::LaunchProcess(setup_path, launch_options, &ph) || |
+ !::GetExitCodeProcess(ph, &exit_code)) { |
+ return false; |
+ } |
- *path = path->AppendASCII(file); |
- return true; |
+ *ret_code = exit_code; |
+ return true; |
+ } |
} |
bool GetEULASentinelFilePath(FilePath* path) { |
- return GetSentinelFilePath(kEULASentinelFile, path); |
+ return InstallUtil::GetSentinelFilePath( |
+ installer::kEULASentinelFile, |
+ BrowserDistribution::GetDistribution(), |
+ path); |
} |
// Returns true if the EULA is required but has not been accepted by this user. |
@@ -234,7 +243,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 +257,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 +274,7 @@ void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { |
} |
} |
} |
+ return true; |
} |
// Installs a task to do an extensions update check once the extensions system |
@@ -498,7 +511,10 @@ bool ImportSettings(Profile* profile, |
} |
bool GetFirstRunSentinelFilePath(FilePath* path) { |
- return GetSentinelFilePath(kSentinelFile, path); |
+ return InstallUtil::GetSentinelFilePath( |
+ kSentinelFile, |
+ BrowserDistribution::GetDistribution(), |
+ path); |
} |
void SetImportPreferencesAndLaunchImport( |
@@ -590,23 +606,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 +637,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 |