15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/first_run/first_run.h" 6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_path.h" 123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/files/file_util.h" 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/lazy_instance.h" 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/ref_counted.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/path_service.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/prefs/pref_service.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/run_loop.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/stringprintf.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "build/build_config.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h" 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/extensions/updater/extension_updater.h" 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/first_run/first_run_internal.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/google/google_brand.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/external_process_importer_host.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/importer_list.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/importer_progress_observer.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/importer_uma.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/importer/profile_writer.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prefs/chrome_pref_service_factory.h" 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profiles_state.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/search_engines/template_url_service_factory.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/shell_integration.h" 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h" 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/signin/signin_promo.h" 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h" 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h" 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/global_error/global_error_service.h" 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/global_error/global_error_service_factory.h" 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/new_tab_ui.h" 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_paths.h" 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h" 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/master_preferences.h" 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/master_preferences_constants.h" 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/util_constants.h" 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h" 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "components/search_engines/template_url_service.h" 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "components/signin/core/browser/signin_manager.h" 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "components/signin/core/browser/signin_tracker.h" 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/browser/notification_observer.h" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_registrar.h" 613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/notification_service.h" 623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/notification_types.h" 633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/user_metrics.h" 643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/web_contents.h" 653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/browser/extension_system.h" 663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h" 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "url/gurl.h" 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::UserMetricsAction; 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace { 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// A bitfield formed from values in AutoImportState to record the state of 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AutoImport. This is used in testing to verify import startup actions that 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// occur before an observer can be registered in the test. 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint16 g_auto_import_state = first_run::AUTO_IMPORT_NONE; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Flags for functions of similar name. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_should_show_welcome_page = false; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool g_should_do_autofill_personal_data_manager_first_run = false; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class acts as an observer for the ImporterProgressObserver::ImportEnded 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// callback. When the import process is started, certain errors may cause 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ImportEnded() to be called synchronously, but the typical case is that 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ImportEnded() is called asynchronously. Thus we have to handle both cases. 86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class ImportEndedObserver : public importer::ImporterProgressObserver { 87a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) public: 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImportEndedObserver() : ended_(false) {} 89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) virtual ~ImportEndedObserver() {} 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // importer::ImporterProgressObserver: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void ImportStarted() OVERRIDE {} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void ImportEnded() OVERRIDE { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ended_ = true; 97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (!callback_for_import_end_.is_null()) 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) callback_for_import_end_.Run(); 99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) void set_callback_for_import_end(const base::Closure& callback) { 102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) callback_for_import_end_ = callback; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ended() const { 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ended_; 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private: 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Set if the import has ended. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ended_; 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Closure callback_for_import_end_; 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ImportEndedObserver); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class that performs delayed first-run tasks that need more of the 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// chrome infrastructure to be up and running before they can be attempted. 1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochclass FirstRunDelayedTasks : public content::NotificationObserver { 1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public: 1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch enum Tasks { 1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch NO_TASK, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INSTALL_EXTENSIONS 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit FirstRunDelayedTasks(Tasks task) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (task == INSTALL_EXTENSIONS) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, 1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::AllSources()); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::AllSources()); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void Observe(int type, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch const content::NotificationDetails& details) OVERRIDE { 1400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch // After processing the notification we always delete ourselves. 1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch if (type == extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Profile* profile = content::Source<Profile>(source).ptr(); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionService* service = 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions::ExtensionSystem::Get(profile)->extension_service(); 1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch DoExtensionWork(service); 1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete this; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Private ctor forces it to be created only in the heap. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~FirstRunDelayedTasks() {} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The extension work is to basically trigger an extension update check. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the extension specified in the master pref is older than the live 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // extension it will get updated which is the same as get it installed. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void DoExtensionWork(ExtensionService* service) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (service) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service->updater()->CheckNow(extensions::ExtensionUpdater::CheckParams()); 1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch content::NotificationRegistrar registrar_; 1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Installs a task to do an extensions update check once the extensions system 1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// is running. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DoDelayedInstallExtensions() { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new FirstRunDelayedTasks(FirstRunDelayedTasks::INSTALL_EXTENSIONS); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DoDelayedInstallExtensionsIfNeeded( 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) installer::MasterPreferences* install_prefs) { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::DictionaryValue* extensions = 0; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (install_prefs->GetExtensionsBlock(&extensions)) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Extensions block found in master preferences"; 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DoDelayedInstallExtensions(); 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 179 180// Sets the |items| bitfield according to whether the import data specified by 181// |import_type| should be be auto imported or not. 182void SetImportItem(PrefService* user_prefs, 183 const char* pref_path, 184 int import_items, 185 int dont_import_items, 186 importer::ImportItem import_type, 187 int* items) { 188 // Work out whether an item is to be imported according to what is specified 189 // in master preferences. 190 bool should_import = false; 191 bool master_pref_set = 192 ((import_items | dont_import_items) & import_type) != 0; 193 bool master_pref = ((import_items & ~dont_import_items) & import_type) != 0; 194 195 if (import_type == importer::HISTORY || 196 (import_type != importer::FAVORITES && 197 first_run::internal::IsOrganicFirstRun())) { 198 // History is always imported unless turned off in master_preferences. 199 // Search engines and home page are imported in organic builds only 200 // unless turned off in master_preferences. 201 should_import = !master_pref_set || master_pref; 202 } else { 203 // Bookmarks are never imported, unless turned on in master_preferences. 204 // Search engine and home page import behaviour is similar in non organic 205 // builds. 206 should_import = master_pref_set && master_pref; 207 } 208 209 // If an import policy is set, import items according to policy. If no master 210 // preference is set, but a corresponding recommended policy is set, import 211 // item according to recommended policy. If both a master preference and a 212 // recommended policy is set, the master preference wins. If neither 213 // recommended nor managed policies are set, import item according to what we 214 // worked out above. 215 if (master_pref_set) 216 user_prefs->SetBoolean(pref_path, should_import); 217 218 if (!user_prefs->FindPreference(pref_path)->IsDefaultValue()) { 219 if (user_prefs->GetBoolean(pref_path)) 220 *items |= import_type; 221 } else { 222 // 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(ExternalProcessImporterHost* importer_host, 235 const importer::SourceProfile& source_profile, 236 Profile* target_profile, 237 uint16 items_to_import) { 238 ImportEndedObserver observer; 239 importer_host->set_observer(&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 base::RunLoop loop; 247 observer.set_callback_for_import_end(loop.QuitClosure()); 248 loop.Run(); 249 observer.set_callback_for_import_end(base::Closure()); 250 } 251} 252 253// Imports bookmarks from an html file whose path is provided by 254// |import_bookmarks_path|. 255void ImportFromFile(Profile* profile, 256 ExternalProcessImporterHost* file_importer_host, 257 const std::string& import_bookmarks_path) { 258 importer::SourceProfile source_profile; 259 source_profile.importer_type = importer::TYPE_BOOKMARKS_FILE; 260 261 const base::FilePath::StringType& import_bookmarks_path_str = 262#if defined(OS_WIN) 263 base::UTF8ToUTF16(import_bookmarks_path); 264#else 265 import_bookmarks_path; 266#endif 267 source_profile.source_path = base::FilePath(import_bookmarks_path_str); 268 269 ImportFromSourceProfile(file_importer_host, source_profile, profile, 270 importer::FAVORITES); 271 g_auto_import_state |= first_run::AUTO_IMPORT_BOOKMARKS_FILE_IMPORTED; 272} 273 274// Imports settings from the first profile in |importer_list|. 275void ImportSettings(Profile* profile, 276 ExternalProcessImporterHost* importer_host, 277 scoped_ptr<ImporterList> importer_list, 278 int items_to_import) { 279 const importer::SourceProfile& source_profile = 280 importer_list->GetSourceProfileAt(0); 281 282 // Ensure that importers aren't requested to import items that they do not 283 // support. If there is no overlap, skip. 284 items_to_import &= source_profile.services_supported; 285 if (items_to_import == 0) 286 return; 287 288 ImportFromSourceProfile(importer_host, source_profile, profile, 289 items_to_import); 290 g_auto_import_state |= first_run::AUTO_IMPORT_PROFILE_IMPORTED; 291} 292 293GURL UrlFromString(const std::string& in) { 294 return GURL(in); 295} 296 297void ConvertStringVectorToGURLVector( 298 const std::vector<std::string>& src, 299 std::vector<GURL>* ret) { 300 ret->resize(src.size()); 301 std::transform(src.begin(), src.end(), ret->begin(), &UrlFromString); 302} 303 304// Show the first run search engine bubble at the first appropriate opportunity. 305// This bubble may be delayed by other UI, like global errors and sync promos. 306class FirstRunBubbleLauncher : public content::NotificationObserver { 307 public: 308 // Show the bubble at the first appropriate opportunity. This function 309 // instantiates a FirstRunBubbleLauncher, which manages its own lifetime. 310 static void ShowFirstRunBubbleSoon(); 311 312 private: 313 FirstRunBubbleLauncher(); 314 virtual ~FirstRunBubbleLauncher(); 315 316 // content::NotificationObserver: 317 virtual void Observe(int type, 318 const content::NotificationSource& source, 319 const content::NotificationDetails& details) OVERRIDE; 320 321 content::NotificationRegistrar registrar_; 322 323 DISALLOW_COPY_AND_ASSIGN(FirstRunBubbleLauncher); 324}; 325 326// static 327void FirstRunBubbleLauncher::ShowFirstRunBubbleSoon() { 328 SetShowFirstRunBubblePref(first_run::FIRST_RUN_BUBBLE_SHOW); 329 // This FirstRunBubbleLauncher instance will manage its own lifetime. 330 new FirstRunBubbleLauncher(); 331} 332 333FirstRunBubbleLauncher::FirstRunBubbleLauncher() { 334 registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 335 content::NotificationService::AllSources()); 336 337 // This notification is required to observe the switch between the sync setup 338 // page and the general settings page. 339 registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 340 content::NotificationService::AllSources()); 341} 342 343FirstRunBubbleLauncher::~FirstRunBubbleLauncher() {} 344 345void FirstRunBubbleLauncher::Observe( 346 int type, 347 const content::NotificationSource& source, 348 const content::NotificationDetails& details) { 349 DCHECK(type == content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME || 350 type == chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED); 351 352 Browser* browser = chrome::FindBrowserWithWebContents( 353 content::Source<content::WebContents>(source).ptr()); 354 if (!browser || !browser->is_type_tabbed()) 355 return; 356 357 // Check the preference to determine if the bubble should be shown. 358 PrefService* prefs = g_browser_process->local_state(); 359 if (!prefs || prefs->GetInteger(prefs::kShowFirstRunBubbleOption) != 360 first_run::FIRST_RUN_BUBBLE_SHOW) { 361 delete this; 362 return; 363 } 364 365 content::WebContents* contents = 366 browser->tab_strip_model()->GetActiveWebContents(); 367 368 // Suppress the first run bubble if a Gaia sign in page, the continue 369 // URL for the sign in page or the sync setup page is showing. 370 if (contents && 371 (contents->GetURL().GetOrigin().spec() == 372 chrome::kChromeUIChromeSigninURL || 373 gaia::IsGaiaSignonRealm(contents->GetURL().GetOrigin()) || 374 signin::IsContinueUrlForWebBasedSigninFlow(contents->GetURL()) || 375 (contents->GetURL() == 376 chrome::GetSettingsUrl(chrome::kSyncSetupSubPage)))) { 377 return; 378 } 379 380 if (contents && contents->GetURL().SchemeIs(content::kChromeUIScheme)) { 381 // Suppress the first run bubble if 'make chrome metro' flow is showing. 382 if (contents->GetURL().host() == chrome::kChromeUIMetroFlowHost) 383 return; 384 385 // Suppress the first run bubble if the NTP sync promo bubble is showing 386 // or if sign in is in progress. 387 if (contents->GetURL().host() == chrome::kChromeUINewTabHost) { 388 Profile* profile = 389 Profile::FromBrowserContext(contents->GetBrowserContext()); 390 SigninManagerBase* manager = 391 SigninManagerFactory::GetForProfile(profile); 392 bool signin_in_progress = manager && manager->AuthInProgress(); 393 bool is_promo_bubble_visible = 394 profile->GetPrefs()->GetBoolean(prefs::kSignInPromoShowNTPBubble); 395 396 if (is_promo_bubble_visible || signin_in_progress) 397 return; 398 } 399 } 400 401 // Suppress the first run bubble if a global error bubble is pending. 402 GlobalErrorService* global_error_service = 403 GlobalErrorServiceFactory::GetForProfile(browser->profile()); 404 if (global_error_service->GetFirstGlobalErrorWithBubbleView() != NULL) 405 return; 406 407 // Reset the preference and notifications to avoid showing the bubble again. 408 prefs->SetInteger(prefs::kShowFirstRunBubbleOption, 409 first_run::FIRST_RUN_BUBBLE_DONT_SHOW); 410 411 // Show the bubble now and destroy this bubble launcher. 412 browser->ShowFirstRunBubble(); 413 delete this; 414} 415 416static base::LazyInstance<base::FilePath> master_prefs_path_for_testing 417 = LAZY_INSTANCE_INITIALIZER; 418 419// Loads master preferences from the master preference file into the installer 420// master preferences. Returns the pointer to installer::MasterPreferences 421// object if successful; otherwise, returns NULL. 422installer::MasterPreferences* LoadMasterPrefs() { 423 base::FilePath master_prefs_path; 424 if (!master_prefs_path_for_testing.Get().empty()) 425 master_prefs_path = master_prefs_path_for_testing.Get(); 426 else 427 master_prefs_path = base::FilePath(first_run::internal::MasterPrefsPath()); 428 if (master_prefs_path.empty()) 429 return NULL; 430 installer::MasterPreferences* install_prefs = 431 new installer::MasterPreferences(master_prefs_path); 432 if (!install_prefs->read_from_file()) { 433 delete install_prefs; 434 return NULL; 435 } 436 437 return install_prefs; 438} 439 440// Makes chrome the user's default browser according to policy or 441// |make_chrome_default_for_user| if no policy is set. 442void ProcessDefaultBrowserPolicy(bool make_chrome_default_for_user) { 443 // Only proceed if chrome can be made default unattended. The interactive case 444 // (Windows 8+) is handled by the first run default browser prompt. 445 if (ShellIntegration::CanSetAsDefaultBrowser() == 446 ShellIntegration::SET_DEFAULT_UNATTENDED) { 447 // The policy has precedence over the user's choice. 448 if (g_browser_process->local_state()->IsManagedPreference( 449 prefs::kDefaultBrowserSettingEnabled)) { 450 if (g_browser_process->local_state()->GetBoolean( 451 prefs::kDefaultBrowserSettingEnabled)) { 452 ShellIntegration::SetAsDefaultBrowser(); 453 } 454 } else if (make_chrome_default_for_user) { 455 ShellIntegration::SetAsDefaultBrowser(); 456 } 457 } 458} 459 460} // namespace 461 462namespace first_run { 463namespace internal { 464 465FirstRunState g_first_run = FIRST_RUN_UNKNOWN; 466 467void SetupMasterPrefsFromInstallPrefs( 468 const installer::MasterPreferences& install_prefs, 469 MasterPrefs* out_prefs) { 470 ConvertStringVectorToGURLVector( 471 install_prefs.GetFirstRunTabs(), &out_prefs->new_tabs); 472 473 install_prefs.GetInt(installer::master_preferences::kDistroPingDelay, 474 &out_prefs->ping_delay); 475 476 bool value = false; 477 if (install_prefs.GetBool( 478 installer::master_preferences::kDistroImportSearchPref, &value)) { 479 if (value) { 480 out_prefs->do_import_items |= importer::SEARCH_ENGINES; 481 } else { 482 out_prefs->dont_import_items |= importer::SEARCH_ENGINES; 483 } 484 } 485 486 // If we're suppressing the first-run bubble, set that preference now. 487 // Otherwise, wait until the user has completed first run to set it, so the 488 // user is guaranteed to see the bubble iff he or she has completed the first 489 // run process. 490 if (install_prefs.GetBool( 491 installer::master_preferences::kDistroSuppressFirstRunBubble, 492 &value) && value) 493 SetShowFirstRunBubblePref(FIRST_RUN_BUBBLE_SUPPRESS); 494 495 if (install_prefs.GetBool( 496 installer::master_preferences::kDistroImportHistoryPref, 497 &value)) { 498 if (value) { 499 out_prefs->do_import_items |= importer::HISTORY; 500 } else { 501 out_prefs->dont_import_items |= importer::HISTORY; 502 } 503 } 504 505 std::string not_used; 506 out_prefs->homepage_defined = install_prefs.GetString( 507 prefs::kHomePage, ¬_used); 508 509 if (install_prefs.GetBool( 510 installer::master_preferences::kDistroImportHomePagePref, 511 &value)) { 512 if (value) { 513 out_prefs->do_import_items |= importer::HOME_PAGE; 514 } else { 515 out_prefs->dont_import_items |= importer::HOME_PAGE; 516 } 517 } 518 519 // Bookmarks are never imported unless specifically turned on. 520 if (install_prefs.GetBool( 521 installer::master_preferences::kDistroImportBookmarksPref, 522 &value)) { 523 if (value) 524 out_prefs->do_import_items |= importer::FAVORITES; 525 else 526 out_prefs->dont_import_items |= importer::FAVORITES; 527 } 528 529 if (install_prefs.GetBool( 530 installer::master_preferences::kMakeChromeDefaultForUser, 531 &value) && value) { 532 out_prefs->make_chrome_default_for_user = true; 533 } 534 535 if (install_prefs.GetBool( 536 installer::master_preferences::kSuppressFirstRunDefaultBrowserPrompt, 537 &value) && value) { 538 out_prefs->suppress_first_run_default_browser_prompt = true; 539 } 540 541 install_prefs.GetString( 542 installer::master_preferences::kDistroImportBookmarksFromFilePref, 543 &out_prefs->import_bookmarks_path); 544 545 out_prefs->variations_seed = install_prefs.GetVariationsSeed(); 546 out_prefs->variations_seed_signature = 547 install_prefs.GetVariationsSeedSignature(); 548 549 install_prefs.GetString( 550 installer::master_preferences::kDistroSuppressDefaultBrowserPromptPref, 551 &out_prefs->suppress_default_browser_prompt_for_version); 552} 553 554bool GetFirstRunSentinelFilePath(base::FilePath* path) { 555 base::FilePath user_data_dir; 556 if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) 557 return false; 558 *path = user_data_dir.Append(chrome::kFirstRunSentinel); 559 return true; 560} 561 562bool CreateSentinel() { 563 base::FilePath first_run_sentinel; 564 return GetFirstRunSentinelFilePath(&first_run_sentinel) && 565 base::WriteFile(first_run_sentinel, "", 0) != -1; 566} 567 568// -- Platform-specific functions -- 569 570#if !defined(OS_LINUX) && !defined(OS_BSD) 571bool IsOrganicFirstRun() { 572 std::string brand; 573 google_brand::GetBrand(&brand); 574 return google_brand::IsOrganicFirstRun(brand); 575} 576#endif 577 578} // namespace internal 579 580MasterPrefs::MasterPrefs() 581 : ping_delay(0), 582 homepage_defined(false), 583 do_import_items(0), 584 dont_import_items(0), 585 make_chrome_default_for_user(false), 586 suppress_first_run_default_browser_prompt(false) { 587} 588 589MasterPrefs::~MasterPrefs() {} 590 591bool IsChromeFirstRun() { 592 if (internal::g_first_run == internal::FIRST_RUN_UNKNOWN) { 593 internal::g_first_run = internal::FIRST_RUN_FALSE; 594 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 595 if (command_line->HasSwitch(switches::kForceFirstRun) || 596 (!command_line->HasSwitch(switches::kNoFirstRun) && 597 !internal::IsFirstRunSentinelPresent())) { 598 internal::g_first_run = internal::FIRST_RUN_TRUE; 599 } 600 } 601 return internal::g_first_run == internal::FIRST_RUN_TRUE; 602} 603 604#if defined(OS_MACOSX) 605bool IsFirstRunSuppressed(const CommandLine& command_line) { 606 return command_line.HasSwitch(switches::kNoFirstRun); 607} 608#endif 609 610void CreateSentinelIfNeeded() { 611 if (IsChromeFirstRun()) 612 internal::CreateSentinel(); 613} 614 615std::string GetPingDelayPrefName() { 616 return base::StringPrintf("%s.%s", 617 installer::master_preferences::kDistroDict, 618 installer::master_preferences::kDistroPingDelay); 619} 620 621void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { 622 registry->RegisterIntegerPref( 623 GetPingDelayPrefName().c_str(), 624 0, 625 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 626} 627 628bool SetShowFirstRunBubblePref(FirstRunBubbleOptions show_bubble_option) { 629 PrefService* local_state = g_browser_process->local_state(); 630 if (!local_state) 631 return false; 632 if (local_state->GetInteger( 633 prefs::kShowFirstRunBubbleOption) != FIRST_RUN_BUBBLE_SUPPRESS) { 634 // Set the new state as long as the bubble wasn't explicitly suppressed 635 // already. 636 local_state->SetInteger(prefs::kShowFirstRunBubbleOption, 637 show_bubble_option); 638 } 639 return true; 640} 641 642void SetShouldShowWelcomePage() { 643 g_should_show_welcome_page = true; 644} 645 646bool ShouldShowWelcomePage() { 647 bool retval = g_should_show_welcome_page; 648 g_should_show_welcome_page = false; 649 return retval; 650} 651 652void SetShouldDoPersonalDataManagerFirstRun() { 653 g_should_do_autofill_personal_data_manager_first_run = true; 654} 655 656bool ShouldDoPersonalDataManagerFirstRun() { 657 bool retval = g_should_do_autofill_personal_data_manager_first_run; 658 g_should_do_autofill_personal_data_manager_first_run = false; 659 return retval; 660} 661 662void LogFirstRunMetric(FirstRunBubbleMetric metric) { 663 UMA_HISTOGRAM_ENUMERATION("FirstRun.SearchEngineBubble", metric, 664 NUM_FIRST_RUN_BUBBLE_METRICS); 665} 666 667void SetMasterPrefsPathForTesting(const base::FilePath& master_prefs) { 668 master_prefs_path_for_testing.Get() = master_prefs; 669} 670 671ProcessMasterPreferencesResult ProcessMasterPreferences( 672 const base::FilePath& user_data_dir, 673 MasterPrefs* out_prefs) { 674 DCHECK(!user_data_dir.empty()); 675 676 scoped_ptr<installer::MasterPreferences> install_prefs(LoadMasterPrefs()); 677 678 // Default value in case master preferences is missing or corrupt, or 679 // ping_delay is missing. 680 out_prefs->ping_delay = 90; 681 if (install_prefs.get()) { 682 if (!internal::ShowPostInstallEULAIfNeeded(install_prefs.get())) 683 return EULA_EXIT_NOW; 684 685 if (!chrome_prefs::InitializePrefsFromMasterPrefs( 686 profiles::GetDefaultProfileDir(user_data_dir), 687 install_prefs->master_dictionary())) { 688 DLOG(ERROR) << "Failed to initialize from master_preferences."; 689 } 690 691 DoDelayedInstallExtensionsIfNeeded(install_prefs.get()); 692 693 internal::SetupMasterPrefsFromInstallPrefs(*install_prefs, out_prefs); 694 } 695 696 return FIRST_RUN_PROCEED; 697} 698 699void AutoImport( 700 Profile* profile, 701 bool homepage_defined, 702 int import_items, 703 int dont_import_items, 704 const std::string& import_bookmarks_path) { 705 base::FilePath local_state_path; 706 PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path); 707 bool local_state_file_exists = base::PathExists(local_state_path); 708 709 // It may be possible to do the if block below asynchronously. In which case, 710 // get rid of this RunLoop. http://crbug.com/366116. 711 base::RunLoop run_loop; 712 scoped_ptr<ImporterList> importer_list(new ImporterList()); 713 importer_list->DetectSourceProfiles( 714 g_browser_process->GetApplicationLocale(), 715 false, // include_interactive_profiles? 716 run_loop.QuitClosure()); 717 run_loop.Run(); 718 719 // Do import if there is an available profile for us to import. 720 if (importer_list->count() > 0) { 721 if (internal::IsOrganicFirstRun()) { 722 // Home page is imported in organic builds only unless turned off or 723 // defined in master_preferences. 724 if (homepage_defined) { 725 dont_import_items |= importer::HOME_PAGE; 726 if (import_items & importer::HOME_PAGE) 727 import_items &= ~importer::HOME_PAGE; 728 } 729 // Search engines are not imported automatically in organic builds if the 730 // user already has a user preferences directory. 731 if (local_state_file_exists) { 732 dont_import_items |= importer::SEARCH_ENGINES; 733 if (import_items & importer::SEARCH_ENGINES) 734 import_items &= ~importer::SEARCH_ENGINES; 735 } 736 } 737 738 PrefService* user_prefs = profile->GetPrefs(); 739 int items = 0; 740 741 SetImportItem(user_prefs, 742 prefs::kImportHistory, 743 import_items, 744 dont_import_items, 745 importer::HISTORY, 746 &items); 747 SetImportItem(user_prefs, 748 prefs::kImportHomepage, 749 import_items, 750 dont_import_items, 751 importer::HOME_PAGE, 752 &items); 753 SetImportItem(user_prefs, 754 prefs::kImportSearchEngine, 755 import_items, 756 dont_import_items, 757 importer::SEARCH_ENGINES, 758 &items); 759 SetImportItem(user_prefs, 760 prefs::kImportBookmarks, 761 import_items, 762 dont_import_items, 763 importer::FAVORITES, 764 &items); 765 766 // Deletes itself. 767 ExternalProcessImporterHost* importer_host = 768 new ExternalProcessImporterHost; 769 770 // Don't show the warning dialog if import fails. 771 importer_host->set_headless(); 772 773 importer::LogImporterUseToMetrics( 774 "AutoImport", importer_list->GetSourceProfileAt(0).importer_type); 775 776 ImportSettings(profile, importer_host, importer_list.Pass(), items); 777 } 778 779 if (!import_bookmarks_path.empty()) { 780 // Deletes itself. 781 ExternalProcessImporterHost* file_importer_host = 782 new ExternalProcessImporterHost; 783 file_importer_host->set_headless(); 784 785 ImportFromFile(profile, file_importer_host, import_bookmarks_path); 786 } 787 788 content::RecordAction(UserMetricsAction("FirstRunDef_Accept")); 789 790 g_auto_import_state |= AUTO_IMPORT_CALLED; 791} 792 793void DoPostImportTasks(Profile* profile, bool make_chrome_default_for_user) { 794 // Only set default browser after import as auto import relies on the current 795 // default browser to know what to import from. 796 ProcessDefaultBrowserPolicy(make_chrome_default_for_user); 797 798 // Display the first run bubble if there is a default search provider. 799 TemplateURLService* template_url = 800 TemplateURLServiceFactory::GetForProfile(profile); 801 if (template_url && template_url->GetDefaultSearchProvider()) 802 FirstRunBubbleLauncher::ShowFirstRunBubbleSoon(); 803 SetShouldShowWelcomePage(); 804 SetShouldDoPersonalDataManagerFirstRun(); 805 806 internal::DoPostImportPlatformSpecificTasks(profile); 807} 808 809uint16 auto_import_state() { 810 return g_auto_import_state; 811} 812 813} // namespace first_run 814