• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/first_run/first_run.h"
6 
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_util.h"
10 #include "base/path_service.h"
11 #include "base/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/first_run/first_run_dialog.h"
15 #include "chrome/browser/first_run/first_run_import_observer.h"
16 #include "chrome/browser/importer/external_process_importer_host.h"
17 #include "chrome/browser/importer/importer_host.h"
18 #include "chrome/browser/importer/importer_list.h"
19 #include "chrome/browser/importer/importer_progress_dialog.h"
20 #include "chrome/browser/importer/importer_progress_observer.h"
21 #include "chrome/browser/metrics/user_metrics.h"
22 #include "chrome/browser/prefs/pref_service.h"
23 #include "chrome/browser/process_singleton.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/browser/search_engines/template_url_model.h"
26 #include "chrome/browser/shell_integration.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/installer/util/master_preferences.h"
31 #include "chrome/installer/util/master_preferences_constants.h"
32 #include "chrome/installer/util/util_constants.h"
33 #include "googleurl/src/gurl.h"
34 
35 #if defined(OS_WIN)
36 // TODO(port): move more code in back from the first_run_win.cc module.
37 #include "chrome/installer/util/google_update_settings.h"
38 #include "chrome/installer/util/install_util.h"
39 #endif
40 
41 namespace {
42 
43 // The kSentinelFile file absence will tell us it is a first run.
44 const char kSentinelFile[] = "First Run";
45 
GetDefaultPrefFilePath(bool create_profile_dir,const FilePath & user_data_dir)46 FilePath GetDefaultPrefFilePath(bool create_profile_dir,
47                                 const FilePath& user_data_dir) {
48   FilePath default_pref_dir =
49       ProfileManager::GetDefaultProfileDir(user_data_dir);
50   if (create_profile_dir) {
51     if (!file_util::PathExists(default_pref_dir)) {
52       if (!file_util::CreateDirectory(default_pref_dir))
53         return FilePath();
54     }
55   }
56   return ProfileManager::GetProfilePrefsPath(default_pref_dir);
57 }
58 
59 }  // namespace
60 
61 // FirstRun -------------------------------------------------------------------
62 
63 FirstRun::FirstRunState FirstRun::first_run_ = FIRST_RUN_UNKNOWN;
64 
MasterPrefs()65 FirstRun::MasterPrefs::MasterPrefs()
66     : ping_delay(0),
67       homepage_defined(false),
68       do_import_items(0),
69       dont_import_items(0),
70       run_search_engine_experiment(false),
71       randomize_search_engine_experiment(false),
72       make_chrome_default(false) {
73 }
74 
~MasterPrefs()75 FirstRun::MasterPrefs::~MasterPrefs() {}
76 
77 // TODO(port): Import switches need to be ported to both Mac and Linux. Not all
78 // import switches here are implemented for Linux. None are implemented for Mac
79 // (as this function will not be called on Mac).
ImportNow(Profile * profile,const CommandLine & cmdline)80 int FirstRun::ImportNow(Profile* profile, const CommandLine& cmdline) {
81   int return_code = true;
82   if (cmdline.HasSwitch(switches::kImportFromFile)) {
83     // Silently import preset bookmarks from file.
84     // This is an OEM scenario.
85     return_code = ImportFromFile(profile, cmdline);
86   }
87   if (cmdline.HasSwitch(switches::kImport)) {
88 #if defined(OS_WIN)
89     return_code = ImportFromBrowser(profile, cmdline);
90 #else
91     NOTIMPLEMENTED();
92 #endif
93   }
94   return return_code;
95 }
96 
97 // static
ProcessMasterPreferences(const FilePath & user_data_dir,MasterPrefs * out_prefs)98 bool FirstRun::ProcessMasterPreferences(const FilePath& user_data_dir,
99                                         MasterPrefs* out_prefs) {
100   DCHECK(!user_data_dir.empty());
101 
102   // The standard location of the master prefs is next to the chrome binary.
103   FilePath master_prefs;
104   if (!PathService::Get(base::DIR_EXE, &master_prefs))
105     return true;
106   master_prefs = master_prefs.AppendASCII(installer::kDefaultMasterPrefs);
107 
108   installer::MasterPreferences prefs(master_prefs);
109   if (!prefs.read_from_file())
110     return true;
111 
112   out_prefs->new_tabs = prefs.GetFirstRunTabs();
113 
114   bool value = false;
115 
116 #if defined(OS_WIN)
117   // RLZ is currently a Windows-only phenomenon.  When it comes to the Mac/
118   // Linux, enable it here.
119   if (!prefs.GetInt(installer::master_preferences::kDistroPingDelay,
120                     &out_prefs->ping_delay)) {
121     // 90 seconds is the default that we want to use in case master
122     // preferences is missing, corrupt or ping_delay is missing.
123     out_prefs->ping_delay = 90;
124   }
125 
126   if (prefs.GetBool(installer::master_preferences::kRequireEula, &value) &&
127       value) {
128     // Show the post-installation EULA. This is done by setup.exe and the
129     // result determines if we continue or not. We wait here until the user
130     // dismisses the dialog.
131 
132     // The actual eula text is in a resource in chrome. We extract it to
133     // a text file so setup.exe can use it as an inner frame.
134     FilePath inner_html;
135     if (WriteEULAtoTempFile(&inner_html)) {
136       int retcode = 0;
137       if (!LaunchSetupWithParam(installer::switches::kShowEula,
138                                 inner_html.value(), &retcode) ||
139           (retcode == installer::EULA_REJECTED)) {
140         LOG(WARNING) << "EULA rejected. Fast exit.";
141         ::ExitProcess(1);
142       }
143       if (retcode == installer::EULA_ACCEPTED) {
144         VLOG(1) << "EULA : no collection";
145         GoogleUpdateSettings::SetCollectStatsConsent(false);
146       } else if (retcode == installer::EULA_ACCEPTED_OPT_IN) {
147         VLOG(1) << "EULA : collection consent";
148         GoogleUpdateSettings::SetCollectStatsConsent(true);
149       }
150     }
151   }
152 #endif
153 
154   if (prefs.GetBool(installer::master_preferences::kAltFirstRunBubble,
155                     &value) && value) {
156     FirstRun::SetOEMFirstRunBubblePref();
157   }
158 
159   FilePath user_prefs = GetDefaultPrefFilePath(true, user_data_dir);
160   if (user_prefs.empty())
161     return true;
162 
163   // The master prefs are regular prefs so we can just copy the file
164   // to the default place and they just work.
165   if (!file_util::CopyFile(master_prefs, user_prefs))
166     return true;
167 
168 #if defined(OS_WIN)
169   DictionaryValue* extensions = 0;
170   if (prefs.GetExtensionsBlock(&extensions)) {
171     VLOG(1) << "Extensions block found in master preferences";
172     DoDelayedInstallExtensions();
173   }
174 #endif
175 
176   if (prefs.GetBool(installer::master_preferences::kDistroImportSearchPref,
177                     &value)) {
178     if (value) {
179       out_prefs->do_import_items |= importer::SEARCH_ENGINES;
180     } else {
181       out_prefs->dont_import_items |= importer::SEARCH_ENGINES;
182     }
183   }
184 
185   // Check to see if search engine logos should be randomized.
186   if (prefs.GetBool(
187           installer::master_preferences::
188               kSearchEngineExperimentRandomizePref,
189           &value) && value) {
190     out_prefs->randomize_search_engine_experiment = true;
191   }
192 
193   // If we're suppressing the first-run bubble, set that preference now.
194   // Otherwise, wait until the user has completed first run to set it, so the
195   // user is guaranteed to see the bubble iff he or she has completed the first
196   // run process.
197   if (prefs.GetBool(
198           installer::master_preferences::kDistroSuppressFirstRunBubble,
199           &value) && value)
200     FirstRun::SetShowFirstRunBubblePref(false);
201 
202   if (prefs.GetBool(
203           installer::master_preferences::kDistroImportHistoryPref,
204           &value)) {
205     if (value) {
206       out_prefs->do_import_items |= importer::HISTORY;
207     } else {
208       out_prefs->dont_import_items |= importer::HISTORY;
209     }
210   }
211 
212   std::string not_used;
213   out_prefs->homepage_defined = prefs.GetString(prefs::kHomePage, &not_used);
214 
215   if (prefs.GetBool(
216           installer::master_preferences::kDistroImportHomePagePref,
217           &value)) {
218     if (value) {
219       out_prefs->do_import_items |= importer::HOME_PAGE;
220     } else {
221       out_prefs->dont_import_items |= importer::HOME_PAGE;
222     }
223   }
224 
225   // Bookmarks are never imported unless specifically turned on.
226   if (prefs.GetBool(
227           installer::master_preferences::kDistroImportBookmarksPref,
228           &value) && value) {
229     out_prefs->do_import_items |= importer::FAVORITES;
230   }
231 
232   if (prefs.GetBool(
233           installer::master_preferences::kMakeChromeDefaultForUser,
234           &value) && value) {
235     out_prefs->make_chrome_default = true;
236   }
237 
238   // TODO(mirandac): Refactor skip-first-run-ui process into regular first run
239   // import process.  http://crbug.com/49647
240   // Note we are skipping all other master preferences if skip-first-run-ui
241   // is *not* specified. (That is, we continue only if skipping first run ui.)
242   if (!prefs.GetBool(
243           installer::master_preferences::kDistroSkipFirstRunPref,
244           &value) || !value) {
245     return true;
246   }
247 
248 #if !defined(OS_WIN)
249   // From here on we won't show first run so we need to do the work to show the
250   // bubble anyway, unless it's already been explicitly suppressed.
251   FirstRun::SetShowFirstRunBubblePref(true);
252 #endif
253 
254   // We need to be able to create the first run sentinel or else we cannot
255   // proceed because ImportSettings will launch the importer process which
256   // would end up here if the sentinel is not present.
257   if (!FirstRun::CreateSentinel())
258     return false;
259 
260   if (prefs.GetBool(installer::master_preferences::kDistroShowWelcomePage,
261                     &value) && value) {
262     FirstRun::SetShowWelcomePagePref();
263   }
264 
265   std::string import_bookmarks_path;
266   prefs.GetString(
267       installer::master_preferences::kDistroImportBookmarksFromFilePref,
268       &import_bookmarks_path);
269 
270 #if defined(OS_WIN)
271   if (!IsOrganicFirstRun()) {
272     // If search engines aren't explicitly imported, don't import.
273     if (!(out_prefs->do_import_items & importer::SEARCH_ENGINES)) {
274       out_prefs->dont_import_items |= importer::SEARCH_ENGINES;
275     }
276     // If home page isn't explicitly imported, don't import.
277     if (!(out_prefs->do_import_items & importer::HOME_PAGE)) {
278       out_prefs->dont_import_items |= importer::HOME_PAGE;
279     }
280     // If history isn't explicitly forbidden, do import.
281     if (!(out_prefs->dont_import_items & importer::HISTORY)) {
282       out_prefs->do_import_items |= importer::HISTORY;
283     }
284   }
285 
286   if (out_prefs->do_import_items || !import_bookmarks_path.empty()) {
287     // There is something to import from the default browser. This launches
288     // the importer process and blocks until done or until it fails.
289     scoped_refptr<ImporterList> importer_list(new ImporterList);
290     importer_list->DetectSourceProfilesHack();
291     if (!FirstRun::ImportSettings(NULL,
292           importer_list->GetSourceProfileAt(0).importer_type,
293           out_prefs->do_import_items,
294           FilePath::FromWStringHack(UTF8ToWide(import_bookmarks_path)),
295           true, NULL)) {
296       LOG(WARNING) << "silent import failed";
297     }
298   }
299 #else
300   if (!import_bookmarks_path.empty()) {
301     // There are bookmarks to import from a file.
302     FilePath path = FilePath::FromWStringHack(UTF8ToWide(
303         import_bookmarks_path));
304     if (!FirstRun::ImportBookmarks(path)) {
305       LOG(WARNING) << "silent bookmark import failed";
306     }
307   }
308 #endif
309 
310   // Even on the first run we only allow for the user choice to take effect if
311   // no policy has been set by the admin.
312   if (!g_browser_process->local_state()->IsManagedPreference(
313           prefs::kDefaultBrowserSettingEnabled)) {
314     if (prefs.GetBool(
315             installer::master_preferences::kMakeChromeDefaultForUser,
316             &value) && value) {
317       ShellIntegration::SetAsDefaultBrowser();
318     }
319   } else {
320     if (g_browser_process->local_state()->GetBoolean(
321             prefs::kDefaultBrowserSettingEnabled)) {
322       ShellIntegration::SetAsDefaultBrowser();
323     }
324   }
325 
326   return false;
327 }
328 
329 // static
IsChromeFirstRun()330 bool FirstRun::IsChromeFirstRun() {
331   if (first_run_ != FIRST_RUN_UNKNOWN)
332     return first_run_ == FIRST_RUN_TRUE;
333 
334   FilePath first_run_sentinel;
335   if (!GetFirstRunSentinelFilePath(&first_run_sentinel) ||
336       file_util::PathExists(first_run_sentinel)) {
337     first_run_ = FIRST_RUN_FALSE;
338     return false;
339   }
340   first_run_ = FIRST_RUN_TRUE;
341   return true;
342 }
343 
344 // static
RemoveSentinel()345 bool FirstRun::RemoveSentinel() {
346   FilePath first_run_sentinel;
347   if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
348     return false;
349   return file_util::Delete(first_run_sentinel, false);
350 }
351 
352 // static
CreateSentinel()353 bool FirstRun::CreateSentinel() {
354   FilePath first_run_sentinel;
355   if (!GetFirstRunSentinelFilePath(&first_run_sentinel))
356     return false;
357   return file_util::WriteFile(first_run_sentinel, "", 0) != -1;
358 }
359 
360 // static
SetShowFirstRunBubblePref(bool show_bubble)361 bool FirstRun::SetShowFirstRunBubblePref(bool show_bubble) {
362   PrefService* local_state = g_browser_process->local_state();
363   if (!local_state)
364     return false;
365   if (!local_state->FindPreference(prefs::kShouldShowFirstRunBubble)) {
366     local_state->RegisterBooleanPref(prefs::kShouldShowFirstRunBubble, false);
367     local_state->SetBoolean(prefs::kShouldShowFirstRunBubble, show_bubble);
368   }
369   return true;
370 }
371 
372 // static
SetShowWelcomePagePref()373 bool FirstRun::SetShowWelcomePagePref() {
374   PrefService* local_state = g_browser_process->local_state();
375   if (!local_state)
376     return false;
377   if (!local_state->FindPreference(prefs::kShouldShowWelcomePage)) {
378     local_state->RegisterBooleanPref(prefs::kShouldShowWelcomePage, false);
379     local_state->SetBoolean(prefs::kShouldShowWelcomePage, true);
380   }
381   return true;
382 }
383 
384 // static
SetPersonalDataManagerFirstRunPref()385 bool FirstRun::SetPersonalDataManagerFirstRunPref() {
386   PrefService* local_state = g_browser_process->local_state();
387   if (!local_state)
388     return false;
389   if (!local_state->FindPreference(
390           prefs::kAutofillPersonalDataManagerFirstRun)) {
391     local_state->RegisterBooleanPref(
392         prefs::kAutofillPersonalDataManagerFirstRun, false);
393     local_state->SetBoolean(prefs::kAutofillPersonalDataManagerFirstRun, true);
394   }
395   return true;
396 }
397 
398 // static
SearchEngineSelectorDisallowed()399 bool FirstRun::SearchEngineSelectorDisallowed() {
400   // For now, the only case in which the search engine dialog should never be
401   // shown is if the locale is Russia.
402   std::string locale = g_browser_process->GetApplicationLocale();
403   return (locale == "ru");
404 }
405 
406 // static
SetOEMFirstRunBubblePref()407 bool FirstRun::SetOEMFirstRunBubblePref() {
408   PrefService* local_state = g_browser_process->local_state();
409   if (!local_state)
410     return false;
411   if (!local_state->FindPreference(prefs::kShouldUseOEMFirstRunBubble)) {
412     local_state->RegisterBooleanPref(prefs::kShouldUseOEMFirstRunBubble,
413                                      false);
414     local_state->SetBoolean(prefs::kShouldUseOEMFirstRunBubble, true);
415   }
416   return true;
417 }
418 
419 // static
SetMinimalFirstRunBubblePref()420 bool FirstRun::SetMinimalFirstRunBubblePref() {
421   PrefService* local_state = g_browser_process->local_state();
422   if (!local_state)
423     return false;
424   if (!local_state->FindPreference(prefs::kShouldUseMinimalFirstRunBubble)) {
425     local_state->RegisterBooleanPref(prefs::kShouldUseMinimalFirstRunBubble,
426                                      false);
427     local_state->SetBoolean(prefs::kShouldUseMinimalFirstRunBubble, true);
428   }
429   return true;
430 }
431 
432 // static
ImportFromFile(Profile * profile,const CommandLine & cmdline)433 int FirstRun::ImportFromFile(Profile* profile, const CommandLine& cmdline) {
434   FilePath file_path = cmdline.GetSwitchValuePath(switches::kImportFromFile);
435   if (file_path.empty()) {
436     NOTREACHED();
437     return false;
438   }
439   scoped_refptr<ImporterHost> importer_host(new ImporterHost);
440   importer_host->set_headless();
441 
442   importer::SourceProfile source_profile;
443   source_profile.importer_type = importer::BOOKMARKS_HTML;
444   source_profile.source_path = file_path;
445 
446   FirstRunImportObserver importer_observer;
447   importer::ShowImportProgressDialog(NULL,
448                                      importer::FAVORITES,
449                                      importer_host,
450                                      &importer_observer,
451                                      source_profile,
452                                      profile,
453                                      true);
454 
455   importer_observer.RunLoop();
456   return importer_observer.import_result();
457 }
458 
459 // static
GetFirstRunSentinelFilePath(FilePath * path)460 bool FirstRun::GetFirstRunSentinelFilePath(FilePath* path) {
461   FilePath first_run_sentinel;
462 
463 #if defined(OS_WIN)
464   FilePath exe_path;
465   if (!PathService::Get(base::DIR_EXE, &exe_path))
466     return false;
467   if (InstallUtil::IsPerUserInstall(exe_path.value().c_str())) {
468     first_run_sentinel = exe_path;
469   } else {
470     if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
471       return false;
472   }
473 #else
474   if (!PathService::Get(chrome::DIR_USER_DATA, &first_run_sentinel))
475     return false;
476 #endif
477 
478   *path = first_run_sentinel.AppendASCII(kSentinelFile);
479   return true;
480 }
481 
482 // static
AutoImport(Profile * profile,bool homepage_defined,int import_items,int dont_import_items,bool search_engine_experiment,bool randomize_search_engine_experiment,bool make_chrome_default,ProcessSingleton * process_singleton)483 void FirstRun::AutoImport(
484     Profile* profile,
485     bool homepage_defined,
486     int import_items,
487     int dont_import_items,
488     bool search_engine_experiment,
489     bool randomize_search_engine_experiment,
490     bool make_chrome_default,
491     ProcessSingleton* process_singleton) {
492   // We need to avoid dispatching new tabs when we are importing because
493   // that will lead to data corruption or a crash. Because there is no UI for
494   // the import process, we pass NULL as the window to bring to the foreground
495   // when a CopyData message comes in; this causes the message to be silently
496   // discarded, which is the correct behavior during the import process.
497   process_singleton->Lock(NULL);
498 
499   PlatformSetup();
500 
501   FilePath local_state_path;
502   PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
503   bool local_state_file_exists = file_util::PathExists(local_state_path);
504 
505   scoped_refptr<ImporterHost> importer_host;
506   // TODO(csilv,mirandac): Out-of-process import has only been qualified on
507   // MacOS X, so we will only use it on that platform since it is required.
508   // Remove this conditional logic once oop import is qualified for
509   // Linux/Windows. http://crbug.com/22142
510 #if defined(OS_MACOSX)
511   importer_host = new ExternalProcessImporterHost;
512 #else
513   importer_host = new ImporterHost;
514 #endif
515 
516   scoped_refptr<ImporterList> importer_list(new ImporterList);
517   importer_list->DetectSourceProfilesHack();
518 
519   // Do import if there is an available profile for us to import.
520   if (importer_list->count() > 0) {
521     // Don't show the warning dialog if import fails.
522     importer_host->set_headless();
523     int items = 0;
524 
525     // History is always imported unless turned off in master_preferences.
526     if (!(dont_import_items & importer::HISTORY))
527       items = items | importer::HISTORY;
528     // Home page is imported in organic builds only unless turned off or
529     // defined in master_preferences.
530     if (IsOrganicFirstRun()) {
531       if (!(dont_import_items & importer::HOME_PAGE) && !homepage_defined)
532         items = items | importer::HOME_PAGE;
533     } else {
534       if (import_items & importer::HOME_PAGE)
535         items = items | importer::HOME_PAGE;
536     }
537     // Search engines are only imported in certain builds unless overridden
538     // in master_preferences. Search engines are not imported automatically
539     // if the user already has a user preferences directory.
540     if (IsOrganicFirstRun()) {
541       if (!(dont_import_items & importer::SEARCH_ENGINES) &&
542           !local_state_file_exists) {
543         items = items | importer::SEARCH_ENGINES;
544       }
545     } else if (import_items & importer::SEARCH_ENGINES) {
546         items = items | importer::SEARCH_ENGINES;
547     }
548 
549     // Bookmarks are never imported, unless turned on in master_preferences.
550     if (import_items & importer::FAVORITES)
551       items = items | importer::FAVORITES;
552 
553     ImportSettings(profile, importer_host, importer_list, items);
554   }
555 
556   UserMetrics::RecordAction(UserMetricsAction("FirstRunDef_Accept"));
557 
558   // Launch the search engine dialog only for certain builds, and only if the
559   // user has not already set preferences.
560   if (IsOrganicFirstRun() && !local_state_file_exists) {
561     // The home page string may be set in the preferences, but the user should
562     // initially use Chrome with the NTP as home page in organic builds.
563     profile->GetPrefs()->SetBoolean(prefs::kHomePageIsNewTabPage, true);
564     first_run::ShowFirstRunDialog(profile, randomize_search_engine_experiment);
565   }
566 
567   if (make_chrome_default)
568     ShellIntegration::SetAsDefaultBrowser();
569 
570   // Don't display the minimal bubble if there is no default search provider.
571   TemplateURLModel* search_engines_model = profile->GetTemplateURLModel();
572   if (search_engines_model &&
573       search_engines_model->GetDefaultSearchProvider()) {
574     FirstRun::SetShowFirstRunBubblePref(true);
575     // Set the first run bubble to minimal.
576     FirstRun::SetMinimalFirstRunBubblePref();
577   }
578   FirstRun::SetShowWelcomePagePref();
579   FirstRun::SetPersonalDataManagerFirstRunPref();
580 
581   process_singleton->Unlock();
582   FirstRun::CreateSentinel();
583 }
584 
585 #if defined(OS_POSIX)
586 namespace {
587 
588 // This class acts as an observer for the ImporterProgressObserver::ImportEnded
589 // callback. When the import process is started, certain errors may cause
590 // ImportEnded() to be called synchronously, but the typical case is that
591 // ImportEnded() is called asynchronously. Thus we have to handle both cases.
592 class ImportEndedObserver : public importer::ImporterProgressObserver {
593  public:
ImportEndedObserver()594   ImportEndedObserver() : ended_(false),
595                           should_quit_message_loop_(false) {}
~ImportEndedObserver()596   virtual ~ImportEndedObserver() {}
597 
598   // importer::ImporterProgressObserver:
ImportStarted()599   virtual void ImportStarted() OVERRIDE {}
ImportItemStarted(importer::ImportItem item)600   virtual void ImportItemStarted(importer::ImportItem item) OVERRIDE {}
ImportItemEnded(importer::ImportItem item)601   virtual void ImportItemEnded(importer::ImportItem item) OVERRIDE {}
ImportEnded()602   virtual void ImportEnded() OVERRIDE {
603     ended_ = true;
604     if (should_quit_message_loop_)
605       MessageLoop::current()->Quit();
606   }
607 
set_should_quit_message_loop()608   void set_should_quit_message_loop() {
609     should_quit_message_loop_ = true;
610   }
611 
ended()612   bool ended() {
613     return ended_;
614   }
615 
616  private:
617   // Set if the import has ended.
618   bool ended_;
619 
620   // Set by the client (via set_should_quit_message_loop) if, when the import
621   // ends, this class should quit the message loop.
622   bool should_quit_message_loop_;
623 };
624 
625 }  // namespace
626 
627 // static
ImportSettings(Profile * profile,scoped_refptr<ImporterHost> importer_host,scoped_refptr<ImporterList> importer_list,int items_to_import)628 bool FirstRun::ImportSettings(Profile* profile,
629                               scoped_refptr<ImporterHost> importer_host,
630                               scoped_refptr<ImporterList> importer_list,
631                               int items_to_import) {
632   const importer::SourceProfile& source_profile =
633       importer_list->GetSourceProfileAt(0);
634 
635   // Ensure that importers aren't requested to import items that they do not
636   // support.
637   items_to_import &= source_profile.services_supported;
638 
639   scoped_ptr<ImportEndedObserver> observer(new ImportEndedObserver);
640   importer_host->SetObserver(observer.get());
641   importer_host->StartImportSettings(source_profile,
642                                      profile,
643                                      items_to_import,
644                                      new ProfileWriter(profile),
645                                      true);
646   // If the import process has not errored out, block on it.
647   if (!observer->ended()) {
648     observer->set_should_quit_message_loop();
649     MessageLoop::current()->Run();
650   }
651 
652   // Unfortunately there's no success/fail signal in ImporterHost.
653   return true;
654 }
655 
656 #endif  // OS_POSIX
657