first_run.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/first_run/first_run.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <algorithm> 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/command_line.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/compiler_specific.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/file_util.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/files/file_path.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/lazy_instance.h" 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/path_service.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/prefs/pref_service.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/stringprintf.h" 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "build/build_config.h" 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/browser_process.h" 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/updater/extension_updater.h" 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/first_run/first_run_internal.h" 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/google/google_util.h" 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/external_process_importer_host.h" 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_host.h" 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_list.h" 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_progress_observer.h" 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/importer_type.h" 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/importer/profile_writer.h" 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h" 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/search_engines/template_url_service.h" 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/search_engines/template_url_service_factory.h" 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/shell_integration.h" 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/signin_manager.h" 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h" 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/signin_tracker.h" 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/browser.h" 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/global_error/global_error_service.h" 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/global_error/global_error_service_factory.h" 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h" 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_notification_types.h" 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_paths.h" 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_switches.h" 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h" 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/url_constants.h" 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/installer/util/master_preferences.h" 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/installer/util/master_preferences_constants.h" 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/installer/util/util_constants.h" 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h" 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/notification_service.h" 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/notification_types.h" 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/user_metrics.h" 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/web_contents.h" 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h" 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "googleurl/src/gurl.h" 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::UserMetricsAction; 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A bitfield formed from values in AutoImportState to record the state of 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// AutoImport. This is used in testing to verify import startup actions that 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// occur before an observer can be registered in the test. 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)uint16 g_auto_import_state = first_run::AUTO_IMPORT_NONE; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Flags for functions of similar name. 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool g_should_show_welcome_page = false; 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool g_should_do_autofill_personal_data_manager_first_run = false; 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This class acts as an observer for the ImporterProgressObserver::ImportEnded 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// callback. When the import process is started, certain errors may cause 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ImportEnded() to be called synchronously, but the typical case is that 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ImportEnded() is called asynchronously. Thus we have to handle both cases. 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class ImportEndedObserver : public importer::ImporterProgressObserver { 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ImportEndedObserver() : ended_(false), 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) should_quit_message_loop_(false) {} 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~ImportEndedObserver() {} 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // importer::ImporterProgressObserver: 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportStarted() OVERRIDE {} 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void ImportEnded() OVERRIDE { 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ended_ = true; 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (should_quit_message_loop_) 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->Quit(); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void set_should_quit_message_loop() { 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) should_quit_message_loop_ = true; 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool ended() const { 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return ended_; 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Set if the import has ended. 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool ended_; 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool should_quit_message_loop_; 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 108 109// Helper class that performs delayed first-run tasks that need more of the 110// chrome infrastructure to be up and running before they can be attempted. 111class FirstRunDelayedTasks : public content::NotificationObserver { 112 public: 113 enum Tasks { 114 NO_TASK, 115 INSTALL_EXTENSIONS 116 }; 117 118 explicit FirstRunDelayedTasks(Tasks task) { 119 if (task == INSTALL_EXTENSIONS) { 120 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, 121 content::NotificationService::AllSources()); 122 } 123 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, 124 content::NotificationService::AllSources()); 125 } 126 127 virtual void Observe(int type, 128 const content::NotificationSource& source, 129 const content::NotificationDetails& details) OVERRIDE { 130 // After processing the notification we always delete ourselves. 131 if (type == chrome::NOTIFICATION_EXTENSIONS_READY) { 132 DoExtensionWork( 133 content::Source<Profile>(source).ptr()->GetExtensionService()); 134 } 135 delete this; 136 } 137 138 private: 139 // Private ctor forces it to be created only in the heap. 140 virtual ~FirstRunDelayedTasks() {} 141 142 // The extension work is to basically trigger an extension update check. 143 // If the extension specified in the master pref is older than the live 144 // extension it will get updated which is the same as get it installed. 145 void DoExtensionWork(ExtensionService* service) { 146 if (service) 147 service->updater()->CheckNow(extensions::ExtensionUpdater::CheckParams()); 148 } 149 150 content::NotificationRegistrar registrar_; 151}; 152 153// Installs a task to do an extensions update check once the extensions system 154// is running. 155void DoDelayedInstallExtensions() { 156 new FirstRunDelayedTasks(FirstRunDelayedTasks::INSTALL_EXTENSIONS); 157} 158 159void DoDelayedInstallExtensionsIfNeeded( 160 installer::MasterPreferences* install_prefs) { 161 DictionaryValue* extensions = 0; 162 if (install_prefs->GetExtensionsBlock(&extensions)) { 163 VLOG(1) << "Extensions block found in master preferences"; 164 DoDelayedInstallExtensions(); 165 } 166} 167 168base::FilePath GetDefaultPrefFilePath(bool create_profile_dir, 169 const base::FilePath& user_data_dir) { 170 base::FilePath default_pref_dir = 171 ProfileManager::GetDefaultProfileDir(user_data_dir); 172 if (create_profile_dir) { 173 if (!file_util::PathExists(default_pref_dir)) { 174 if (!file_util::CreateDirectory(default_pref_dir)) 175 return base::FilePath(); 176 } 177 } 178 return ProfileManager::GetProfilePrefsPath(default_pref_dir); 179} 180 181// Sets the |items| bitfield according to whether the import data specified by 182// |import_type| should be be auto imported or not. 183void SetImportItem(PrefService* user_prefs, 184 const char* pref_path, 185 int import_items, 186 int dont_import_items, 187 importer::ImportItem import_type, 188 int* items) { 189 // Work out whether an item is to be imported according to what is specified 190 // in master preferences. 191 bool should_import = false; 192 bool master_pref_set = 193 ((import_items | dont_import_items) & import_type) != 0; 194 bool master_pref = ((import_items & ~dont_import_items) & import_type) != 0; 195 196 if (import_type == importer::HISTORY || 197 (import_type != importer::FAVORITES && 198 first_run::internal::IsOrganicFirstRun())) { 199 // History is always imported unless turned off in master_preferences. 200 // Search engines and home page are imported in organic builds only 201 // unless turned off in master_preferences. 202 should_import = !master_pref_set || master_pref; 203 } else { 204 // Bookmarks are never imported, unless turned on in master_preferences. 205 // Search engine and home page import behaviour is similar in non organic 206 // builds. 207 should_import = master_pref_set && master_pref; 208 } 209 210 // If an import policy is set, import items according to policy. If no master 211 // preference is set, but a corresponding recommended policy is set, import 212 // item according to recommended policy. If both a master preference and a 213 // recommended policy is set, the master preference wins. If neither 214 // recommended nor managed policies are set, import item according to what we 215 // worked out above. 216 if (master_pref_set) 217 user_prefs->SetBoolean(pref_path, should_import); 218 219 if (!user_prefs->FindPreference(pref_path)->IsDefaultValue()) { 220 if (user_prefs->GetBoolean(pref_path)) 221 *items |= import_type; 222 } else { // no policy (recommended or managed) is set 223 if (should_import) 224 *items |= import_type; 225 } 226 227 user_prefs->ClearPref(pref_path); 228} 229 230// Launches the import, via |importer_host|, from |source_profile| into 231// |target_profile| for the items specified in the |items_to_import| bitfield. 232// This may be done in a separate process depending on the platform, but it will 233// always block until done. 234void ImportFromSourceProfile(ImporterHost* importer_host, 235 const importer::SourceProfile& source_profile, 236 Profile* target_profile, 237 uint16 items_to_import) { 238 ImportEndedObserver observer; 239 importer_host->SetObserver(&observer); 240 importer_host->StartImportSettings(source_profile, 241 target_profile, 242 items_to_import, 243 new ProfileWriter(target_profile)); 244 // If the import process has not errored out, block on it. 245 if (!observer.ended()) { 246 observer.set_should_quit_message_loop(); 247 base::MessageLoop::current()->Run(); 248 } 249} 250 251// Imports bookmarks from an html file whose path is provided by 252// |import_bookmarks_path|. 253void ImportFromFile(Profile* profile, 254 ImporterHost* file_importer_host, 255 const std::string& import_bookmarks_path) { 256 importer::SourceProfile source_profile; 257 source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE; 258 259 const base::FilePath::StringType& import_bookmarks_path_str = 260#if defined(OS_WIN) 261 UTF8ToUTF16(import_bookmarks_path); 262#else 263 import_bookmarks_path; 264#endif 265 source_profile.source_path = base::FilePath(import_bookmarks_path_str); 266 267 ImportFromSourceProfile(file_importer_host, source_profile, profile, 268 importer::FAVORITES); 269 g_auto_import_state |= first_run::AUTO_IMPORT_BOOKMARKS_FILE_IMPORTED; 270} 271 272// Imports settings from the first profile in |importer_list|. 273void ImportSettings(Profile* profile, 274 ImporterHost* importer_host, 275 scoped_refptr<ImporterList> importer_list, 276 int items_to_import) { 277 const importer::SourceProfile& source_profile = 278 importer_list->GetSourceProfileAt(0); 279 280 // Ensure that importers aren't requested to import items that they do not 281 // support. If there is no overlap, skip. 282 items_to_import &= source_profile.services_supported; 283 if (items_to_import == 0) 284 return; 285 286 ImportFromSourceProfile(importer_host, source_profile, profile, 287 items_to_import); 288 g_auto_import_state |= first_run::AUTO_IMPORT_PROFILE_IMPORTED; 289} 290 291GURL UrlFromString(const std::string& in) { 292 return GURL(in); 293} 294 295void ConvertStringVectorToGURLVector( 296 const std::vector<std::string>& src, 297 std::vector<GURL>* ret) { 298 ret->resize(src.size()); 299 std::transform(src.begin(), src.end(), ret->begin(), &UrlFromString); 300} 301 302} // namespace 303 304namespace first_run { 305namespace internal { 306 307FirstRunState first_run_ = FIRST_RUN_UNKNOWN; 308 309static base::LazyInstance<base::FilePath> master_prefs_path_for_testing 310 = LAZY_INSTANCE_INITIALIZER; 311 312installer::MasterPreferences* 313 LoadMasterPrefs(base::FilePath* master_prefs_path) { 314 if (!master_prefs_path_for_testing.Get().empty()) 315 *master_prefs_path = master_prefs_path_for_testing.Get(); 316 else 317 *master_prefs_path = base::FilePath(MasterPrefsPath()); 318 if (master_prefs_path->empty()) 319 return NULL; 320 installer::MasterPreferences* install_prefs = 321 new installer::MasterPreferences(*master_prefs_path); 322 if (!install_prefs->read_from_file()) { 323 delete install_prefs; 324 return NULL; 325 } 326 327 return install_prefs; 328} 329 330bool CopyPrefFile(const base::FilePath& user_data_dir, 331 const base::FilePath& master_prefs_path) { 332 base::FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir); 333 if (user_prefs.empty()) 334 return false; 335 336 // The master prefs are regular prefs so we can just copy the file 337 // to the default place and they just work. 338 return file_util::CopyFile(master_prefs_path, user_prefs); 339} 340 341void SetupMasterPrefsFromInstallPrefs( 342 const installer::MasterPreferences& install_prefs, 343 MasterPrefs* out_prefs) { 344 ConvertStringVectorToGURLVector( 345 install_prefs.GetFirstRunTabs(), &out_prefs->new_tabs); 346 347 install_prefs.GetInt(installer::master_preferences::kDistroPingDelay, 348 &out_prefs->ping_delay); 349 350 bool value = false; 351 if (install_prefs.GetBool( 352 installer::master_preferences::kDistroImportSearchPref, &value)) { 353 if (value) { 354 out_prefs->do_import_items |= importer::SEARCH_ENGINES; 355 } else { 356 out_prefs->dont_import_items |= importer::SEARCH_ENGINES; 357 } 358 } 359 360 // If we're suppressing the first-run bubble, set that preference now. 361 // Otherwise, wait until the user has completed first run to set it, so the 362 // user is guaranteed to see the bubble iff he or she has completed the first 363 // run process. 364 if (install_prefs.GetBool( 365 installer::master_preferences::kDistroSuppressFirstRunBubble, 366 &value) && value) 367 SetShowFirstRunBubblePref(FIRST_RUN_BUBBLE_SUPPRESS); 368 369 if (install_prefs.GetBool( 370 installer::master_preferences::kDistroImportHistoryPref, 371 &value)) { 372 if (value) { 373 out_prefs->do_import_items |= importer::HISTORY; 374 } else { 375 out_prefs->dont_import_items |= importer::HISTORY; 376 } 377 } 378 379 std::string not_used; 380 out_prefs->homepage_defined = install_prefs.GetString( 381 prefs::kHomePage, ¬_used); 382 383 if (install_prefs.GetBool( 384 installer::master_preferences::kDistroImportHomePagePref, 385 &value)) { 386 if (value) { 387 out_prefs->do_import_items |= importer::HOME_PAGE; 388 } else { 389 out_prefs->dont_import_items |= importer::HOME_PAGE; 390 } 391 } 392 393 // Bookmarks are never imported unless specifically turned on. 394 if (install_prefs.GetBool( 395 installer::master_preferences::kDistroImportBookmarksPref, 396 &value)) { 397 if (value) 398 out_prefs->do_import_items |= importer::FAVORITES; 399 else 400 out_prefs->dont_import_items |= importer::FAVORITES; 401 } 402 403 if (install_prefs.GetBool( 404 installer::master_preferences::kMakeChromeDefaultForUser, 405 &value) && value) { 406 out_prefs->make_chrome_default = true; 407 } 408 409 if (install_prefs.GetBool( 410 installer::master_preferences::kSuppressFirstRunDefaultBrowserPrompt, 411 &value) && value) { 412 out_prefs->suppress_first_run_default_browser_prompt = true; 413 } 414 415 install_prefs.GetString( 416 installer::master_preferences::kDistroImportBookmarksFromFilePref, 417 &out_prefs->import_bookmarks_path); 418 419 out_prefs->variations_seed = install_prefs.GetVariationsSeed(); 420 421 install_prefs.GetString( 422 installer::master_preferences::kDistroSuppressDefaultBrowserPromptPref, 423 &out_prefs->suppress_default_browser_prompt_for_version); 424} 425 426void SetDefaultBrowser(installer::MasterPreferences* install_prefs){ 427 // Even on the first run we only allow for the user choice to take effect if 428 // no policy has been set by the admin. 429 if (!g_browser_process->local_state()->IsManagedPreference( 430 prefs::kDefaultBrowserSettingEnabled)) { 431 bool value = false; 432 if (install_prefs->GetBool( 433 installer::master_preferences::kMakeChromeDefaultForUser, 434 &value) && value) { 435 ShellIntegration::SetAsDefaultBrowser(); 436 } 437 } else { 438 if (g_browser_process->local_state()->GetBoolean( 439 prefs::kDefaultBrowserSettingEnabled)) { 440 ShellIntegration::SetAsDefaultBrowser(); 441 } 442 } 443} 444 445// -- Platform-specific functions -- 446 447#if !defined(OS_LINUX) && !defined(OS_BSD) 448bool IsOrganicFirstRun() { 449 std::string brand; 450 google_util::GetBrand(&brand); 451 return google_util::IsOrganicFirstRun(brand); 452} 453#endif 454 455} // namespace internal 456} // namespace first_run 457 458namespace first_run { 459 460MasterPrefs::MasterPrefs() 461 : ping_delay(0), 462 homepage_defined(false), 463 do_import_items(0), 464 dont_import_items(0), 465 make_chrome_default(false), 466 suppress_first_run_default_browser_prompt(false) { 467} 468 469MasterPrefs::~MasterPrefs() {} 470 471bool IsChromeFirstRun() { 472 if (internal::first_run_ != internal::FIRST_RUN_UNKNOWN) 473 return internal::first_run_ == internal::FIRST_RUN_TRUE; 474 475 base::FilePath first_run_sentinel; 476 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel) || 477 file_util::PathExists(first_run_sentinel)) { 478 internal::first_run_ = internal::FIRST_RUN_FALSE; 479 return false; 480 } 481 internal::first_run_ = internal::FIRST_RUN_TRUE; 482 return true; 483} 484 485bool CreateSentinel() { 486 base::FilePath first_run_sentinel; 487 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel)) 488 return false; 489 return file_util::WriteFile(first_run_sentinel, "", 0) != -1; 490} 491 492std::string GetPingDelayPrefName() { 493 return base::StringPrintf("%s.%s", 494 installer::master_preferences::kDistroDict, 495 installer::master_preferences::kDistroPingDelay); 496} 497 498void RegisterUserPrefs(user_prefs::PrefRegistrySyncable* registry) { 499 registry->RegisterIntegerPref( 500 GetPingDelayPrefName().c_str(), 501 0, 502 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 503} 504 505bool RemoveSentinel() { 506 base::FilePath first_run_sentinel; 507 if (!internal::GetFirstRunSentinelFilePath(&first_run_sentinel)) 508 return false; 509 return file_util::Delete(first_run_sentinel, false); 510} 511 512bool SetShowFirstRunBubblePref(FirstRunBubbleOptions show_bubble_option) { 513 PrefService* local_state = g_browser_process->local_state(); 514 if (!local_state) 515 return false; 516 if (local_state->GetInteger( 517 prefs::kShowFirstRunBubbleOption) != FIRST_RUN_BUBBLE_SUPPRESS) { 518 // Set the new state as long as the bubble wasn't explicitly suppressed 519 // already. 520 local_state->SetInteger(prefs::kShowFirstRunBubbleOption, 521 show_bubble_option); 522 } 523 return true; 524} 525 526void SetShouldShowWelcomePage() { 527 g_should_show_welcome_page = true; 528} 529 530bool ShouldShowWelcomePage() { 531 bool retval = g_should_show_welcome_page; 532 g_should_show_welcome_page = false; 533 return retval; 534} 535 536void SetShouldDoPersonalDataManagerFirstRun() { 537 g_should_do_autofill_personal_data_manager_first_run = true; 538} 539 540bool ShouldDoPersonalDataManagerFirstRun() { 541 bool retval = g_should_do_autofill_personal_data_manager_first_run; 542 g_should_do_autofill_personal_data_manager_first_run = false; 543 return retval; 544} 545 546void LogFirstRunMetric(FirstRunBubbleMetric metric) { 547 UMA_HISTOGRAM_ENUMERATION("FirstRun.SearchEngineBubble", metric, 548 NUM_FIRST_RUN_BUBBLE_METRICS); 549} 550 551// static 552void FirstRunBubbleLauncher::ShowFirstRunBubbleSoon() { 553 SetShowFirstRunBubblePref(FIRST_RUN_BUBBLE_SHOW); 554 // This FirstRunBubbleLauncher instance will manage its own lifetime. 555 new FirstRunBubbleLauncher(); 556} 557 558FirstRunBubbleLauncher::FirstRunBubbleLauncher() { 559 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 560 content::NotificationService::AllSources()); 561} 562 563FirstRunBubbleLauncher::~FirstRunBubbleLauncher() {} 564 565void FirstRunBubbleLauncher::Observe( 566 int type, 567 const content::NotificationSource& source, 568 const content::NotificationDetails& details) { 569 DCHECK_EQ(type, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME); 570 Browser* browser = chrome::FindBrowserWithWebContents( 571 content::Source<content::WebContents>(source).ptr()); 572 if (!browser || !browser->is_type_tabbed()) 573 return; 574 575 // Check the preference to determine if the bubble should be shown. 576 PrefService* prefs = g_browser_process->local_state(); 577 if (!prefs || prefs->GetInteger( 578 prefs::kShowFirstRunBubbleOption) != FIRST_RUN_BUBBLE_SHOW) { 579 delete this; 580 return; 581 } 582 583 content::WebContents* contents = 584 browser->tab_strip_model()->GetActiveWebContents(); 585 586 // Suppress the first run bubble if a Gaia sign in page or the continue 587 // URL for the sign in page is showing. 588 if (contents && 589 (gaia::IsGaiaSignonRealm(contents->GetURL().GetOrigin()) || 590 SyncPromoUI::IsContinueUrlForWebBasedSigninFlow(contents->GetURL()))) { 591 return; 592 } 593 594 if (contents && contents->GetURL().SchemeIs(chrome::kChromeUIScheme)) { 595 // Suppress the first run bubble if 'make chrome metro' flow is showing. 596 if (contents->GetURL().host() == chrome::kChromeUIMetroFlowHost) 597 return; 598 599 // Suppress the first run bubble if the NTP sync promo bubble is showing 600 // or if sign in is in progress. 601 if (contents->GetURL().host() == chrome::kChromeUINewTabHost) { 602 Profile* profile = 603 Profile::FromBrowserContext(contents->GetBrowserContext()); 604 SigninManagerBase* manager = 605 SigninManagerFactory::GetForProfile(profile); 606 bool signin_in_progress = manager && 607 (!manager->GetAuthenticatedUsername().empty() && 608 SigninTracker::GetSigninState(profile, NULL) != 609 SigninTracker::SIGNIN_COMPLETE); 610 bool is_promo_bubble_visible = 611 profile->GetPrefs()->GetBoolean(prefs::kSyncPromoShowNTPBubble); 612 613 if (is_promo_bubble_visible || signin_in_progress) 614 return; 615 } 616 } 617 618 // Suppress the first run bubble if a global error bubble is pending. 619 GlobalErrorService* global_error_service = 620 GlobalErrorServiceFactory::GetForProfile(browser->profile()); 621 if (global_error_service->GetFirstGlobalErrorWithBubbleView() != NULL) 622 return; 623 624 // Reset the preference and notifications to avoid showing the bubble again. 625 prefs->SetInteger(prefs::kShowFirstRunBubbleOption, 626 FIRST_RUN_BUBBLE_DONT_SHOW); 627 628 // Show the bubble now and destroy this bubble launcher. 629 browser->ShowFirstRunBubble(); 630 delete this; 631} 632 633void SetMasterPrefsPathForTesting(const base::FilePath& master_prefs) { 634 internal::master_prefs_path_for_testing.Get() = master_prefs; 635} 636 637ProcessMasterPreferencesResult ProcessMasterPreferences( 638 const base::FilePath& user_data_dir, 639 MasterPrefs* out_prefs) { 640 DCHECK(!user_data_dir.empty()); 641 642#if defined(OS_CHROMEOS) 643 // Chrome OS has its own out-of-box-experience code. Create the sentinel to 644 // mark the fact that we've run once but skip the full first-run flow. 645 CreateSentinel(); 646 return SKIP_FIRST_RUN_TASKS; 647#endif 648 649 base::FilePath master_prefs_path; 650 scoped_ptr<installer::MasterPreferences> 651 install_prefs(internal::LoadMasterPrefs(&master_prefs_path)); 652 653 // Default value in case master preferences is missing or corrupt, or 654 // ping_delay is missing. 655 out_prefs->ping_delay = 90; 656 if (install_prefs.get()) { 657 if (!internal::ShowPostInstallEULAIfNeeded(install_prefs.get())) 658 return EULA_EXIT_NOW; 659 660 if (!internal::CopyPrefFile(user_data_dir, master_prefs_path)) 661 DLOG(ERROR) << "Failed to copy master_preferences to user data dir."; 662 663 DoDelayedInstallExtensionsIfNeeded(install_prefs.get()); 664 665 internal::SetupMasterPrefsFromInstallPrefs(*install_prefs, out_prefs); 666 667 internal::SetDefaultBrowser(install_prefs.get()); 668 } 669 670 return DO_FIRST_RUN_TASKS; 671} 672 673void AutoImport( 674 Profile* profile, 675 bool homepage_defined, 676 int import_items, 677 int dont_import_items, 678 const std::string& import_bookmarks_path) { 679#if !defined(USE_AURA) 680 // Deletes itself. 681 ImporterHost* importer_host; 682 // TODO(csilv,mirandac): Out-of-process import has only been qualified on 683 // MacOS X and Windows, so we will only use it on those platforms. 684 // Linux still uses the in-process import (http://crbug.com/56816). 685#if defined(OS_MACOSX) || defined(OS_WIN) 686 importer_host = new ExternalProcessImporterHost; 687#else 688 importer_host = new ImporterHost; 689#endif 690 691 base::FilePath local_state_path; 692 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path); 693 bool local_state_file_exists = file_util::PathExists(local_state_path); 694 695 scoped_refptr<ImporterList> importer_list(new ImporterList(NULL)); 696 importer_list->DetectSourceProfilesHack(); 697 698 // Do import if there is an available profile for us to import. 699 if (importer_list->count() > 0) { 700 // Don't show the warning dialog if import fails. 701 importer_host->set_headless(); 702 int items = 0; 703 704 if (internal::IsOrganicFirstRun()) { 705 // Home page is imported in organic builds only unless turned off or 706 // defined in master_preferences. 707 if (homepage_defined) { 708 dont_import_items |= importer::HOME_PAGE; 709 if (import_items & importer::HOME_PAGE) 710 import_items &= ~importer::HOME_PAGE; 711 } 712 // Search engines are not imported automatically in organic builds if the 713 // user already has a user preferences directory. 714 if (local_state_file_exists) { 715 dont_import_items |= importer::SEARCH_ENGINES; 716 if (import_items & importer::SEARCH_ENGINES) 717 import_items &= ~importer::SEARCH_ENGINES; 718 } 719 } 720 721 PrefService* user_prefs = profile->GetPrefs(); 722 723 SetImportItem(user_prefs, 724 prefs::kImportHistory, 725 import_items, 726 dont_import_items, 727 importer::HISTORY, 728 &items); 729 SetImportItem(user_prefs, 730 prefs::kImportHomepage, 731 import_items, 732 dont_import_items, 733 importer::HOME_PAGE, 734 &items); 735 SetImportItem(user_prefs, 736 prefs::kImportSearchEngine, 737 import_items, 738 dont_import_items, 739 importer::SEARCH_ENGINES, 740 &items); 741 SetImportItem(user_prefs, 742 prefs::kImportBookmarks, 743 import_items, 744 dont_import_items, 745 importer::FAVORITES, 746 &items); 747 748 importer::LogImporterUseToMetrics( 749 "AutoImport", importer_list->GetSourceProfileAt(0).importer_type); 750 751 ImportSettings(profile, importer_host, importer_list, items); 752 } 753 754 if (!import_bookmarks_path.empty()) { 755 // Deletes itself. 756 ImporterHost* file_importer_host; 757 // TODO(gab): Make Linux use OOP import as well (http://crbug.com/56816) and 758 // get rid of these ugly ifdefs. 759#if defined(OS_MACOSX) || defined(OS_WIN) 760 file_importer_host = new ExternalProcessImporterHost; 761#else 762 file_importer_host = new ImporterHost; 763#endif 764 file_importer_host->set_headless(); 765 766 ImportFromFile(profile, file_importer_host, import_bookmarks_path); 767 } 768 769 content::RecordAction(UserMetricsAction("FirstRunDef_Accept")); 770 771#endif // !defined(USE_AURA) 772 g_auto_import_state |= AUTO_IMPORT_CALLED; 773} 774 775void DoPostImportTasks(Profile* profile, bool make_chrome_default) { 776 if (make_chrome_default && 777 ShellIntegration::CanSetAsDefaultBrowser() == 778 ShellIntegration::SET_DEFAULT_UNATTENDED) { 779 ShellIntegration::SetAsDefaultBrowser(); 780 } 781 782 // Display the first run bubble if there is a default search provider. 783 TemplateURLService* template_url = 784 TemplateURLServiceFactory::GetForProfile(profile); 785 if (template_url && template_url->GetDefaultSearchProvider()) 786 FirstRunBubbleLauncher::ShowFirstRunBubbleSoon(); 787 SetShouldShowWelcomePage(); 788 SetShouldDoPersonalDataManagerFirstRun(); 789 790 internal::DoPostImportPlatformSpecificTasks(profile); 791} 792 793uint16 auto_import_state() { 794 return g_auto_import_state; 795} 796 797} // namespace first_run 798