OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/first_run/first_run.h" | 5 #include "chrome/browser/first_run/first_run.h" |
6 | 6 |
| 7 #include <shellapi.h> |
7 #include <shlobj.h> | 8 #include <shlobj.h> |
8 #include <windows.h> | 9 #include <windows.h> |
9 | 10 |
10 #include "base/environment.h" | 11 #include "base/environment.h" |
11 #include "base/file_util.h" | 12 #include "base/file_util.h" |
12 #include "base/path_service.h" | 13 #include "base/path_service.h" |
13 #include "base/process_util.h" | 14 #include "base/process_util.h" |
14 #include "base/string_number_conversions.h" | 15 #include "base/string_number_conversions.h" |
15 #include "base/string_split.h" | 16 #include "base/string_split.h" |
16 #include "base/stringprintf.h" | 17 #include "base/stringprintf.h" |
17 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
| 19 #include "base/win/metro.h" |
18 #include "base/win/object_watcher.h" | 20 #include "base/win/object_watcher.h" |
19 #include "base/win/windows_version.h" | 21 #include "base/win/windows_version.h" |
20 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/browser_process.h" |
21 #include "chrome/browser/extensions/extension_service.h" | 23 #include "chrome/browser/extensions/extension_service.h" |
22 #include "chrome/browser/extensions/updater/extension_updater.h" | 24 #include "chrome/browser/extensions/updater/extension_updater.h" |
23 #include "chrome/browser/first_run/first_run_import_observer.h" | 25 #include "chrome/browser/first_run/first_run_import_observer.h" |
24 #include "chrome/browser/first_run/first_run_internal.h" | 26 #include "chrome/browser/first_run/first_run_internal.h" |
25 #include "chrome/browser/importer/importer_host.h" | 27 #include "chrome/browser/importer/importer_host.h" |
26 #include "chrome/browser/importer/importer_list.h" | 28 #include "chrome/browser/importer/importer_list.h" |
27 #include "chrome/browser/importer/importer_progress_dialog.h" | 29 #include "chrome/browser/importer/importer_progress_dialog.h" |
(...skipping 17 matching lines...) Expand all Loading... |
45 #include "content/public/browser/notification_service.h" | 47 #include "content/public/browser/notification_service.h" |
46 #include "content/public/browser/user_metrics.h" | 48 #include "content/public/browser/user_metrics.h" |
47 #include "google_update/google_update_idl.h" | 49 #include "google_update/google_update_idl.h" |
48 #include "grit/chromium_strings.h" | 50 #include "grit/chromium_strings.h" |
49 #include "grit/generated_resources.h" | 51 #include "grit/generated_resources.h" |
50 #include "grit/locale_settings.h" | 52 #include "grit/locale_settings.h" |
51 #include "grit/theme_resources.h" | 53 #include "grit/theme_resources.h" |
52 #include "ui/base/l10n/l10n_util.h" | 54 #include "ui/base/l10n/l10n_util.h" |
53 #include "ui/base/layout.h" | 55 #include "ui/base/layout.h" |
54 #include "ui/base/ui_base_switches.h" | 56 #include "ui/base/ui_base_switches.h" |
| 57 #include "ui/base/win/shell.h" |
55 | 58 |
56 namespace { | 59 namespace { |
57 | 60 |
58 const char kEULASentinelFile[] = "EULA Accepted"; | |
59 | |
60 // Helper class that performs delayed first-run tasks that need more of the | 61 // Helper class that performs delayed first-run tasks that need more of the |
61 // chrome infrastructure to be up and running before they can be attempted. | 62 // chrome infrastructure to be up and running before they can be attempted. |
62 class FirstRunDelayedTasks : public content::NotificationObserver { | 63 class FirstRunDelayedTasks : public content::NotificationObserver { |
63 public: | 64 public: |
64 enum Tasks { | 65 enum Tasks { |
65 NO_TASK, | 66 NO_TASK, |
66 INSTALL_EXTENSIONS | 67 INSTALL_EXTENSIONS |
67 }; | 68 }; |
68 | 69 |
69 explicit FirstRunDelayedTasks(Tasks task) { | 70 explicit FirstRunDelayedTasks(Tasks task) { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 } | 138 } |
138 | 139 |
139 void PlatformSetup(Profile* profile) { | 140 void PlatformSetup(Profile* profile) { |
140 CreateChromeDesktopShortcut(); | 141 CreateChromeDesktopShortcut(); |
141 | 142 |
142 // Windows 7 has deprecated the quick launch bar. | 143 // Windows 7 has deprecated the quick launch bar. |
143 if (base::win::GetVersion() < base::win::VERSION_WIN7) | 144 if (base::win::GetVersion() < base::win::VERSION_WIN7) |
144 CreateChromeQuickLaunchShortcut(); | 145 CreateChromeQuickLaunchShortcut(); |
145 } | 146 } |
146 | 147 |
147 // Launches the setup exe with the given parameter/value on the command-line, | 148 // Launches the setup exe with the given parameter/value on the command-line. |
148 // waits for its termination, returns its exit code in |*ret_code|, and | 149 // For non-metro Windows, it waits for its termination, returns its exit code |
149 // returns true if the exit code is valid. | 150 // in |*ret_code|, and returns true if the exit code is valid. |
150 bool LaunchSetupWithParam(const std::string& param, | 151 // For metro Windows, it launches setup via ShellExecuteEx and returns in order |
151 const FilePath::StringType& value, | 152 // to bounce the user back to the desktop, then returns immediately. |
152 int* ret_code) { | 153 bool LaunchSetupForEula(const FilePath::StringType& value, int* ret_code) { |
153 FilePath exe_path; | 154 FilePath exe_dir; |
154 if (!PathService::Get(base::DIR_MODULE, &exe_path)) | 155 if (!PathService::Get(base::DIR_MODULE, &exe_dir)) |
155 return false; | 156 return false; |
156 exe_path = exe_path.Append(installer::kInstallerDir); | 157 exe_dir = exe_dir.Append(installer::kInstallerDir); |
157 exe_path = exe_path.Append(installer::kSetupExe); | 158 FilePath exe_path = exe_dir.Append(installer::kSetupExe); |
158 base::ProcessHandle ph; | 159 base::ProcessHandle ph; |
159 CommandLine cl(exe_path); | 160 |
160 cl.AppendSwitchNative(param, value); | 161 CommandLine cl(CommandLine::NO_PROGRAM); |
| 162 cl.AppendSwitchNative(installer::switches::kShowEula, value); |
161 | 163 |
162 CommandLine* browser_command_line = CommandLine::ForCurrentProcess(); | 164 CommandLine* browser_command_line = CommandLine::ForCurrentProcess(); |
163 if (browser_command_line->HasSwitch(switches::kChromeFrame)) { | 165 if (browser_command_line->HasSwitch(switches::kChromeFrame)) { |
164 cl.AppendSwitch(switches::kChromeFrame); | 166 cl.AppendSwitch(switches::kChromeFrame); |
165 } | 167 } |
166 | 168 |
167 // TODO(evan): should this use options.wait = true? | 169 if (base::win::IsMetroProcess()) { |
168 if (!base::LaunchProcess(cl, base::LaunchOptions(), &ph)) | 170 cl.AppendSwitch(installer::switches::kShowEulaForMetro); |
| 171 |
| 172 // This obscure use of the 'log usage' mask for windows 8 is documented here |
| 173 // http://go.microsoft.com/fwlink/?LinkID=243079. It causes the desktop |
| 174 // process to receive focus. Pass SEE_MASK_FLAG_NO_UI to avoid hangs if an |
| 175 // error occurs since the UI can't be shown from a metro process. |
| 176 ui::win::OpenAnyViaShell(exe_path.value(), |
| 177 exe_dir.value(), |
| 178 cl.GetCommandLineString(), |
| 179 SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_FLAG_NO_UI); |
169 return false; | 180 return false; |
170 DWORD wr = ::WaitForSingleObject(ph, INFINITE); | 181 } else { |
171 if (wr != WAIT_OBJECT_0) | 182 base::LaunchOptions launch_options; |
172 return false; | 183 launch_options.wait = true; |
173 return (TRUE == ::GetExitCodeProcess(ph, reinterpret_cast<DWORD*>(ret_code))); | 184 CommandLine setup_path(exe_path); |
174 } | 185 setup_path.AppendArguments(cl, false); |
175 | 186 |
176 // Populates |path| with the path to |file| in the sentinel directory. This is | 187 DWORD exit_code = 0; |
177 // the application directory for user-level installs, and the default user data | 188 if (!base::LaunchProcess(setup_path, launch_options, &ph) || |
178 // dir for system-level installs. Returns false on error. | 189 !::GetExitCodeProcess(ph, &exit_code)) { |
179 bool GetSentinelFilePath(const char* file, FilePath* path) { | 190 return false; |
180 FilePath exe_path; | 191 } |
181 if (!PathService::Get(base::DIR_EXE, &exe_path)) | |
182 return false; | |
183 if (InstallUtil::IsPerUserInstall(exe_path.value().c_str())) | |
184 *path = exe_path; | |
185 else if (!PathService::Get(chrome::DIR_USER_DATA, path)) | |
186 return false; | |
187 | 192 |
188 *path = path->AppendASCII(file); | 193 *ret_code = exit_code; |
189 return true; | 194 return true; |
| 195 } |
190 } | 196 } |
191 | 197 |
192 bool GetEULASentinelFilePath(FilePath* path) { | 198 bool GetEULASentinelFilePath(FilePath* path) { |
193 return GetSentinelFilePath(kEULASentinelFile, path); | 199 return InstallUtil::GetSentinelFilePath( |
| 200 installer::kEULASentinelFile, |
| 201 BrowserDistribution::GetDistribution(), |
| 202 path); |
194 } | 203 } |
195 | 204 |
196 // Returns true if the EULA is required but has not been accepted by this user. | 205 // Returns true if the EULA is required but has not been accepted by this user. |
197 // The EULA is considered having been accepted if the user has gotten past | 206 // The EULA is considered having been accepted if the user has gotten past |
198 // first run in the "other" environment (desktop or metro). | 207 // first run in the "other" environment (desktop or metro). |
199 bool IsEULANotAccepted(installer::MasterPreferences* install_prefs) { | 208 bool IsEULANotAccepted(installer::MasterPreferences* install_prefs) { |
200 bool value = false; | 209 bool value = false; |
201 if (install_prefs->GetBool(installer::master_preferences::kRequireEula, | 210 if (install_prefs->GetBool(installer::master_preferences::kRequireEula, |
202 &value) && value) { | 211 &value) && value) { |
203 FilePath eula_sentinel; | 212 FilePath eula_sentinel; |
(...skipping 23 matching lines...) Expand all Loading... |
227 | 236 |
228 // Creates the sentinel indicating that the EULA was required and has been | 237 // Creates the sentinel indicating that the EULA was required and has been |
229 // accepted. | 238 // accepted. |
230 bool CreateEULASentinel() { | 239 bool CreateEULASentinel() { |
231 FilePath eula_sentinel; | 240 FilePath eula_sentinel; |
232 if (!GetEULASentinelFilePath(&eula_sentinel)) | 241 if (!GetEULASentinelFilePath(&eula_sentinel)) |
233 return false; | 242 return false; |
234 return file_util::WriteFile(eula_sentinel, "", 0) != -1; | 243 return file_util::WriteFile(eula_sentinel, "", 0) != -1; |
235 } | 244 } |
236 | 245 |
237 void ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { | 246 // Shows the EULA dialog if required. Returns true if the EULA is accepted, |
| 247 // returns false if the EULA has not been accepted, in which case the browser |
| 248 // should exit. |
| 249 bool ShowPostInstallEULAIfNeeded(installer::MasterPreferences* install_prefs) { |
238 if (IsEULANotAccepted(install_prefs)) { | 250 if (IsEULANotAccepted(install_prefs)) { |
239 // Show the post-installation EULA. This is done by setup.exe and the | 251 // Show the post-installation EULA. This is done by setup.exe and the |
240 // result determines if we continue or not. We wait here until the user | 252 // result determines if we continue or not. We wait here until the user |
241 // dismisses the dialog. | 253 // dismisses the dialog. |
242 | 254 |
243 // The actual eula text is in a resource in chrome. We extract it to | 255 // The actual eula text is in a resource in chrome. We extract it to |
244 // a text file so setup.exe can use it as an inner frame. | 256 // a text file so setup.exe can use it as an inner frame. |
245 FilePath inner_html; | 257 FilePath inner_html; |
246 if (WriteEULAtoTempFile(&inner_html)) { | 258 if (WriteEULAtoTempFile(&inner_html)) { |
247 int retcode = 0; | 259 int retcode = 0; |
248 if (!LaunchSetupWithParam(installer::switches::kShowEula, | 260 if (!LaunchSetupForEula(inner_html.value(), &retcode) || |
249 inner_html.value(), &retcode) || | |
250 (retcode != installer::EULA_ACCEPTED && | 261 (retcode != installer::EULA_ACCEPTED && |
251 retcode != installer::EULA_ACCEPTED_OPT_IN)) { | 262 retcode != installer::EULA_ACCEPTED_OPT_IN)) { |
252 LOG(WARNING) << "EULA rejected. Fast exit."; | 263 LOG(WARNING) << "EULA flow requires fast exit."; |
253 ::ExitProcess(1); | 264 return false; |
254 } | 265 } |
255 CreateEULASentinel(); | 266 CreateEULASentinel(); |
| 267 |
256 if (retcode == installer::EULA_ACCEPTED) { | 268 if (retcode == installer::EULA_ACCEPTED) { |
257 VLOG(1) << "EULA : no collection"; | 269 VLOG(1) << "EULA : no collection"; |
258 GoogleUpdateSettings::SetCollectStatsConsent(false); | 270 GoogleUpdateSettings::SetCollectStatsConsent(false); |
259 } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) { | 271 } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) { |
260 VLOG(1) << "EULA : collection consent"; | 272 VLOG(1) << "EULA : collection consent"; |
261 GoogleUpdateSettings::SetCollectStatsConsent(true); | 273 GoogleUpdateSettings::SetCollectStatsConsent(true); |
262 } | 274 } |
263 } | 275 } |
264 } | 276 } |
| 277 return true; |
265 } | 278 } |
266 | 279 |
267 // Installs a task to do an extensions update check once the extensions system | 280 // Installs a task to do an extensions update check once the extensions system |
268 // is running. | 281 // is running. |
269 void DoDelayedInstallExtensions() { | 282 void DoDelayedInstallExtensions() { |
270 new FirstRunDelayedTasks(FirstRunDelayedTasks::INSTALL_EXTENSIONS); | 283 new FirstRunDelayedTasks(FirstRunDelayedTasks::INSTALL_EXTENSIONS); |
271 } | 284 } |
272 | 285 |
273 void DoDelayedInstallExtensionsIfNeeded( | 286 void DoDelayedInstallExtensionsIfNeeded( |
274 installer::MasterPreferences* install_prefs) { | 287 installer::MasterPreferences* install_prefs) { |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 int items_to_import) { | 504 int items_to_import) { |
492 return ImportSettingsWin( | 505 return ImportSettingsWin( |
493 profile, | 506 profile, |
494 importer_list->GetSourceProfileAt(0).importer_type, | 507 importer_list->GetSourceProfileAt(0).importer_type, |
495 items_to_import, | 508 items_to_import, |
496 FilePath(), | 509 FilePath(), |
497 false); | 510 false); |
498 } | 511 } |
499 | 512 |
500 bool GetFirstRunSentinelFilePath(FilePath* path) { | 513 bool GetFirstRunSentinelFilePath(FilePath* path) { |
501 return GetSentinelFilePath(kSentinelFile, path); | 514 return InstallUtil::GetSentinelFilePath( |
| 515 kSentinelFile, |
| 516 BrowserDistribution::GetDistribution(), |
| 517 path); |
502 } | 518 } |
503 | 519 |
504 void SetImportPreferencesAndLaunchImport( | 520 void SetImportPreferencesAndLaunchImport( |
505 MasterPrefs* out_prefs, | 521 MasterPrefs* out_prefs, |
506 installer::MasterPreferences* install_prefs) { | 522 installer::MasterPreferences* install_prefs) { |
507 std::string import_bookmarks_path; | 523 std::string import_bookmarks_path; |
508 install_prefs->GetString( | 524 install_prefs->GetString( |
509 installer::master_preferences::kDistroImportBookmarksFromFilePref, | 525 installer::master_preferences::kDistroImportBookmarksFromFilePref, |
510 &import_bookmarks_path); | 526 &import_bookmarks_path); |
511 | 527 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 } | 599 } |
584 | 600 |
585 FilePath MasterPrefsPath() { | 601 FilePath MasterPrefsPath() { |
586 // The standard location of the master prefs is next to the chrome binary. | 602 // The standard location of the master prefs is next to the chrome binary. |
587 FilePath master_prefs; | 603 FilePath master_prefs; |
588 if (!PathService::Get(base::DIR_EXE, &master_prefs)) | 604 if (!PathService::Get(base::DIR_EXE, &master_prefs)) |
589 return FilePath(); | 605 return FilePath(); |
590 return master_prefs.AppendASCII(installer::kDefaultMasterPrefs); | 606 return master_prefs.AppendASCII(installer::kDefaultMasterPrefs); |
591 } | 607 } |
592 | 608 |
593 bool ProcessMasterPreferences(const FilePath& user_data_dir, | 609 ProcessMasterPreferencesResult ProcessMasterPreferences( |
594 MasterPrefs* out_prefs) { | 610 const FilePath& user_data_dir, |
| 611 MasterPrefs* out_prefs) { |
595 DCHECK(!user_data_dir.empty()); | 612 DCHECK(!user_data_dir.empty()); |
596 | 613 |
597 FilePath master_prefs_path; | 614 FilePath master_prefs_path; |
598 scoped_ptr<installer::MasterPreferences> | 615 scoped_ptr<installer::MasterPreferences> |
599 install_prefs(internal::LoadMasterPrefs(&master_prefs_path)); | 616 install_prefs(internal::LoadMasterPrefs(&master_prefs_path)); |
600 if (!install_prefs.get()) | 617 if (!install_prefs.get()) |
601 return true; | 618 return SHOW_FIRST_RUN; |
602 | 619 |
603 out_prefs->new_tabs = install_prefs->GetFirstRunTabs(); | 620 out_prefs->new_tabs = install_prefs->GetFirstRunTabs(); |
604 | 621 |
605 internal::SetRLZPref(out_prefs, install_prefs.get()); | 622 internal::SetRLZPref(out_prefs, install_prefs.get()); |
606 ShowPostInstallEULAIfNeeded(install_prefs.get()); | 623 |
| 624 if (!ShowPostInstallEULAIfNeeded(install_prefs.get())) |
| 625 return EULA_EXIT_NOW; |
607 | 626 |
608 if (!internal::CopyPrefFile(user_data_dir, master_prefs_path)) | 627 if (!internal::CopyPrefFile(user_data_dir, master_prefs_path)) |
609 return true; | 628 return SHOW_FIRST_RUN; |
610 | 629 |
611 DoDelayedInstallExtensionsIfNeeded(install_prefs.get()); | 630 DoDelayedInstallExtensionsIfNeeded(install_prefs.get()); |
612 | 631 |
613 internal::SetupMasterPrefsFromInstallPrefs(out_prefs, | 632 internal::SetupMasterPrefsFromInstallPrefs(out_prefs, |
614 install_prefs.get()); | 633 install_prefs.get()); |
615 | 634 |
616 // TODO(mirandac): Refactor skip-first-run-ui process into regular first run | 635 // TODO(mirandac): Refactor skip-first-run-ui process into regular first run |
617 // import process. http://crbug.com/49647 | 636 // import process. http://crbug.com/49647 |
618 // Note we are skipping all other master preferences if skip-first-run-ui | 637 // Note we are skipping all other master preferences if skip-first-run-ui |
619 // is *not* specified. (That is, we continue only if skipping first run ui.) | 638 // is *not* specified. (That is, we continue only if skipping first run ui.) |
620 if (!internal::SkipFirstRunUI(install_prefs.get())) | 639 if (!internal::SkipFirstRunUI(install_prefs.get())) |
621 return true; | 640 return SHOW_FIRST_RUN; |
622 | 641 |
623 // We need to be able to create the first run sentinel or else we cannot | 642 // We need to be able to create the first run sentinel or else we cannot |
624 // proceed because ImportSettings will launch the importer process which | 643 // proceed because ImportSettings will launch the importer process which |
625 // would end up here if the sentinel is not present. | 644 // would end up here if the sentinel is not present. |
626 if (!CreateSentinel()) | 645 if (!CreateSentinel()) |
627 return false; | 646 return SKIP_FIRST_RUN; |
628 | 647 |
629 internal::SetShowWelcomePagePrefIfNeeded(install_prefs.get()); | 648 internal::SetShowWelcomePagePrefIfNeeded(install_prefs.get()); |
630 internal::SetImportPreferencesAndLaunchImport(out_prefs, install_prefs.get()); | 649 internal::SetImportPreferencesAndLaunchImport(out_prefs, install_prefs.get()); |
631 internal::SetDefaultBrowser(install_prefs.get()); | 650 internal::SetDefaultBrowser(install_prefs.get()); |
632 | 651 |
633 return false; | 652 return SKIP_FIRST_RUN; |
634 } | 653 } |
635 | 654 |
636 } // namespace first_run | 655 } // namespace first_run |
OLD | NEW |