1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/startup/startup_browser_creator.h"
6
7 #include <stddef.h>
8
9 #include <set>
10 #include <string>
11 #include <utility>
12
13 #include "apps/switches.h"
14 #include "base/bind.h"
15 #include "base/callback_helpers.h"
16 #include "base/command_line.h"
17 #include "base/feature_list.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/lazy_instance.h"
21 #include "base/logging.h"
22 #include "base/memory/ptr_util.h"
23 #include "base/metrics/histogram_base.h"
24 #include "base/metrics/histogram_macros.h"
25 #include "base/metrics/statistics_recorder.h"
26 #include "base/scoped_observer.h"
27 #include "base/strings/string16.h"
28 #include "base/strings/string_tokenizer.h"
29 #include "base/task/thread_pool.h"
30 #include "base/threading/scoped_blocking_call.h"
31 #include "base/trace_event/trace_event.h"
32 #include "build/branding_buildflags.h"
33 #include "build/build_config.h"
34 #include "chrome/browser/app_mode/app_mode_utils.h"
35 #include "chrome/browser/apps/platform_apps/app_load_service.h"
36 #include "chrome/browser/browser_process.h"
37 #include "chrome/browser/chromeos/app_mode/kiosk_app_types.h"
38 #include "chrome/browser/chromeos/profiles/profile_helper.h"
39 #include "chrome/browser/extensions/startup_helper.h"
40 #include "chrome/browser/first_run/first_run.h"
41 #include "chrome/browser/prefs/incognito_mode_prefs.h"
42 #include "chrome/browser/prefs/session_startup_pref.h"
43 #include "chrome/browser/profiles/profile.h"
44 #include "chrome/browser/profiles/profile_attributes_entry.h"
45 #include "chrome/browser/profiles/profile_attributes_storage.h"
46 #include "chrome/browser/profiles/profile_manager.h"
47 #include "chrome/browser/profiles/profile_observer.h"
48 #include "chrome/browser/profiles/profiles_state.h"
49 #include "chrome/browser/search_engines/template_url_service_factory.h"
50 #include "chrome/browser/ui/browser.h"
51 #include "chrome/browser/ui/browser_finder.h"
52 #include "chrome/browser/ui/browser_list.h"
53 #include "chrome/browser/ui/browser_list_observer.h"
54 #include "chrome/browser/ui/browser_window.h"
55 #include "chrome/browser/ui/startup/launch_mode_recorder.h"
56 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
57 #include "chrome/browser/ui/ui_features.h"
58 #include "chrome/common/buildflags.h"
59 #include "chrome/common/chrome_constants.h"
60 #include "chrome/common/chrome_features.h"
61 #include "chrome/common/chrome_switches.h"
62 #include "chrome/common/pref_names.h"
63 #include "chrome/common/url_constants.h"
64 #include "components/prefs/pref_registry_simple.h"
65 #include "components/prefs/pref_service.h"
66 #include "components/search_engines/util.h"
67 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
68 #include "components/url_formatter/url_fixer.h"
69 #include "content/public/browser/browser_task_traits.h"
70 #include "content/public/browser/browser_thread.h"
71 #include "content/public/browser/child_process_security_policy.h"
72 #include "content/public/browser/navigation_controller.h"
73 #include "content/public/common/content_switches.h"
74 #include "extensions/common/switches.h"
75 #include "printing/buildflags/buildflags.h"
76
77 #if defined(OS_CHROMEOS)
78 #include "chrome/browser/chromeos/app_mode/app_launch_utils.h"
79 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
80 #include "chrome/browser/lifetime/application_lifetime.h"
81 #include "chromeos/constants/chromeos_switches.h"
82 #include "chromeos/cryptohome/cryptohome_parameters.h"
83 #include "components/user_manager/user_manager.h"
84 #else
85 #include "chrome/browser/extensions/api/messaging/native_messaging_launch_from_native.h"
86 #include "chrome/browser/ui/profile_picker.h"
87 #include "chrome/browser/ui/user_manager.h"
88 #endif
89
90 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
91 #include "ui/events/devices/x11/touch_factory_x11.h" // nogncheck
92 #endif
93
94 #if defined(OS_MAC)
95 #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut_mac.h"
96 #endif
97
98 #if defined(OS_WIN)
99 #include "base/strings/utf_string_conversions.h"
100 #include "chrome/browser/metrics/jumplist_metrics_win.h"
101 #include "chrome/browser/notifications/notification_platform_bridge_win.h"
102 #include "chrome/browser/notifications/win/notification_launch_id.h"
103 #include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
104 #include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
105 #include "chrome/credential_provider/common/gcp_strings.h"
106 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
107 #include "chrome/browser/printing/print_dialog_cloud_win.h"
108 #endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
109 #endif // defined(OS_WIN)
110
111 #if defined(USE_X11)
112 #include "ui/base/ui_base_features.h"
113 #endif
114
115 using content::BrowserThread;
116 using content::ChildProcessSecurityPolicy;
117
118 namespace {
119
120 // Keeps track on which profiles have been launched.
121 class ProfileLaunchObserver : public ProfileObserver,
122 public BrowserListObserver {
123 public:
ProfileLaunchObserver()124 ProfileLaunchObserver() { BrowserList::AddObserver(this); }
125 ProfileLaunchObserver(const ProfileLaunchObserver&) = delete;
126 ProfileLaunchObserver& operator=(const ProfileLaunchObserver&) = delete;
~ProfileLaunchObserver()127 ~ProfileLaunchObserver() override { BrowserList::RemoveObserver(this); }
128
129 // BrowserListObserver:
OnBrowserAdded(Browser * browser)130 void OnBrowserAdded(Browser* browser) override {
131 opened_profiles_.insert(browser->profile());
132 MaybeActivateProfile();
133 }
134
135 // ProfileObserver:
OnProfileWillBeDestroyed(Profile * profile)136 void OnProfileWillBeDestroyed(Profile* profile) override {
137 observed_profiles_.Remove(profile);
138 launched_profiles_.erase(profile);
139 opened_profiles_.erase(profile);
140 if (profile == profile_to_activate_)
141 profile_to_activate_ = nullptr;
142 // If this profile was the last launched one without an opened window,
143 // then we may be ready to activate |profile_to_activate_|.
144 MaybeActivateProfile();
145 }
146
HasBeenLaunched(const Profile * profile) const147 bool HasBeenLaunched(const Profile* profile) const {
148 return launched_profiles_.find(profile) != launched_profiles_.end();
149 }
150
AddLaunched(Profile * profile)151 void AddLaunched(Profile* profile) {
152 if (!observed_profiles_.IsObserving(profile))
153 observed_profiles_.Add(profile);
154 launched_profiles_.insert(profile);
155 if (chrome::FindBrowserWithProfile(profile)) {
156 // A browser may get opened before we get initialized (e.g., in tests),
157 // so we never see the OnBrowserAdded() for it.
158 opened_profiles_.insert(profile);
159 }
160 }
161
Clear()162 void Clear() {
163 launched_profiles_.clear();
164 opened_profiles_.clear();
165 }
166
activated_profile()167 bool activated_profile() { return activated_profile_; }
168
set_profile_to_activate(Profile * profile)169 void set_profile_to_activate(Profile* profile) {
170 if (!observed_profiles_.IsObserving(profile))
171 observed_profiles_.Add(profile);
172 profile_to_activate_ = profile;
173 MaybeActivateProfile();
174 }
175
176 private:
MaybeActivateProfile()177 void MaybeActivateProfile() {
178 if (!profile_to_activate_)
179 return;
180 // Check that browsers have been opened for all the launched profiles.
181 // Note that browsers opened for profiles that were not added as launched
182 // profiles are simply ignored.
183 auto i = launched_profiles_.begin();
184 for (; i != launched_profiles_.end(); ++i) {
185 if (opened_profiles_.find(*i) == opened_profiles_.end())
186 return;
187 }
188 // Asynchronous post to give a chance to the last window to completely
189 // open and activate before trying to activate |profile_to_activate_|.
190 content::GetUIThreadTaskRunner({})->PostTask(
191 FROM_HERE, base::BindOnce(&ProfileLaunchObserver::ActivateProfile,
192 base::Unretained(this)));
193 // Avoid posting more than once before ActivateProfile gets called.
194 observed_profiles_.RemoveAll();
195 BrowserList::RemoveObserver(this);
196 }
197
ActivateProfile()198 void ActivateProfile() {
199 // We need to test again, in case the profile got deleted in the mean time.
200 if (profile_to_activate_) {
201 Browser* browser = chrome::FindBrowserWithProfile(profile_to_activate_);
202 // |profile| may never get launched, e.g., if it only had
203 // incognito Windows and one of them was used to exit Chrome.
204 // So it won't have a browser in that case.
205 if (browser)
206 browser->window()->Activate();
207 // No need try to activate this profile again.
208 profile_to_activate_ = nullptr;
209 }
210 // Assign true here, even if no browser was actually activated, so that
211 // the test can stop waiting, and fail gracefully when needed.
212 activated_profile_ = true;
213 }
214
215 // These are the profiles that get launched by
216 // StartupBrowserCreator::LaunchBrowser.
217 std::set<const Profile*> launched_profiles_;
218 // These are the profiles for which at least one browser window has been
219 // opened. This is needed to know when it is safe to activate
220 // |profile_to_activate_|, otherwise, new browser windows being opened will
221 // be activated on top of it.
222 std::set<const Profile*> opened_profiles_;
223 // This is null until the profile to activate has been chosen. This value
224 // should only be set once all profiles have been launched, otherwise,
225 // activation may not happen after the launch of newer profiles.
226 Profile* profile_to_activate_ = nullptr;
227 // Set once we attempted to activate a profile. We only get one shot at this.
228 bool activated_profile_ = false;
229 ScopedObserver<Profile, ProfileObserver> observed_profiles_{this};
230 };
231
232 base::LazyInstance<ProfileLaunchObserver>::DestructorAtExit
233 profile_launch_observer = LAZY_INSTANCE_INITIALIZER;
234
235 // Dumps the current set of the browser process's histograms to |output_file|.
236 // The file is overwritten if it exists. This function should only be called in
237 // the blocking pool.
DumpBrowserHistograms(const base::FilePath & output_file)238 void DumpBrowserHistograms(const base::FilePath& output_file) {
239 std::string output_string(
240 base::StatisticsRecorder::ToJSON(base::JSON_VERBOSITY_LEVEL_FULL));
241
242 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
243 base::BlockingType::MAY_BLOCK);
244 base::WriteFile(output_file, output_string.data(),
245 static_cast<int>(output_string.size()));
246 }
247
248 // Returns whether |profile| can be opened during Chrome startup without
249 // explicit user action.
CanOpenProfileOnStartup(Profile * profile)250 bool CanOpenProfileOnStartup(Profile* profile) {
251 #if defined(OS_CHROMEOS)
252 // On ChromeOS, the user has already chosen and logged into the profile before
253 // Chrome starts up.
254 return true;
255 #else
256 // Profiles that require signin are not available.
257 ProfileAttributesEntry* entry = nullptr;
258 if (g_browser_process->profile_manager()
259 ->GetProfileAttributesStorage()
260 .GetProfileAttributesWithPath(profile->GetPath(), &entry) &&
261 entry->IsSigninRequired()) {
262 return false;
263 }
264
265 // Guest or system profiles are not available unless a separate process
266 // already has a window open for the profile.
267 if (profile->IsEphemeralGuestProfile())
268 return chrome::GetBrowserCount(profile->GetOriginalProfile()) > 0;
269
270 return (!profile->IsGuestSession() && !profile->IsSystemProfile()) ||
271 (chrome::GetBrowserCount(profile->GetPrimaryOTRProfile()) > 0);
272 #endif
273 }
274
ShowUserManagerOnStartup()275 void ShowUserManagerOnStartup() {
276 #if !defined(OS_CHROMEOS)
277 UserManager::Show(base::FilePath(),
278 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
279 #endif // !defined(OS_CHROMEOS)
280 }
281
IsSilentLaunchEnabled(const base::CommandLine & command_line,const Profile * profile)282 bool IsSilentLaunchEnabled(const base::CommandLine& command_line,
283 const Profile* profile) {
284 // Note: This check should have been done in ProcessCmdLineImpl()
285 // before calling this function. However chromeos/login/login_utils.cc
286 // calls this function directly (see comments there) so it has to be checked
287 // again.
288
289 if (command_line.HasSwitch(switches::kSilentLaunch))
290 return true;
291
292 #if defined(OS_CHROMEOS)
293 return profile->GetPrefs()->GetBoolean(
294 prefs::kStartupBrowserWindowLaunchSuppressed);
295 #endif // defined(OS_CHROMEOS)
296
297 return false;
298 }
299
300 } // namespace
301
302 StartupBrowserCreator::StartupBrowserCreator() = default;
303
304 StartupBrowserCreator::~StartupBrowserCreator() = default;
305
306 // static
307 bool StartupBrowserCreator::was_restarted_read_ = false;
308
309 // static
310 bool StartupBrowserCreator::in_synchronous_profile_launch_ = false;
311
AddFirstRunTab(const GURL & url)312 void StartupBrowserCreator::AddFirstRunTab(const GURL& url) {
313 first_run_tabs_.push_back(url);
314 }
315
Start(const base::CommandLine & cmd_line,const base::FilePath & cur_dir,Profile * last_used_profile,const Profiles & last_opened_profiles)316 bool StartupBrowserCreator::Start(const base::CommandLine& cmd_line,
317 const base::FilePath& cur_dir,
318 Profile* last_used_profile,
319 const Profiles& last_opened_profiles) {
320 TRACE_EVENT0("startup", "StartupBrowserCreator::Start");
321 SCOPED_UMA_HISTOGRAM_TIMER("Startup.StartupBrowserCreator_Start");
322 return ProcessCmdLineImpl(cmd_line, cur_dir, true, last_used_profile,
323 last_opened_profiles);
324 }
325
326 // static
InSynchronousProfileLaunch()327 bool StartupBrowserCreator::InSynchronousProfileLaunch() {
328 return in_synchronous_profile_launch_;
329 }
330
LaunchBrowser(const base::CommandLine & command_line,Profile * profile,const base::FilePath & cur_dir,chrome::startup::IsProcessStartup process_startup,chrome::startup::IsFirstRun is_first_run,std::unique_ptr<LaunchModeRecorder> launch_mode_recorder)331 bool StartupBrowserCreator::LaunchBrowser(
332 const base::CommandLine& command_line,
333 Profile* profile,
334 const base::FilePath& cur_dir,
335 chrome::startup::IsProcessStartup process_startup,
336 chrome::startup::IsFirstRun is_first_run,
337 std::unique_ptr<LaunchModeRecorder> launch_mode_recorder) {
338 DCHECK(profile);
339 #if defined(OS_WIN)
340 DCHECK(!command_line.HasSwitch(credential_provider::kGcpwSigninSwitch));
341 DCHECK(!command_line.HasSwitch(switches::kNotificationLaunchId));
342 #endif // defined(OS_WIN)
343 in_synchronous_profile_launch_ =
344 process_startup == chrome::startup::IS_PROCESS_STARTUP;
345
346 // Continue with the incognito profile from here on if Incognito mode is
347 // forced.
348 if (IncognitoModePrefs::ShouldLaunchIncognito(command_line,
349 profile->GetPrefs())) {
350 profile = profile->GetPrimaryOTRProfile();
351 } else if (command_line.HasSwitch(switches::kIncognito)) {
352 LOG(WARNING) << "Incognito mode disabled by policy, launching a normal "
353 << "browser session.";
354 }
355
356 if (profiles::IsGuestModeRequested(command_line,
357 g_browser_process->local_state(),
358 /* show_warning= */ true)) {
359 profile = g_browser_process->profile_manager()->GetProfile(
360 ProfileManager::GetGuestProfilePath());
361 if (!profile->IsEphemeralGuestProfile())
362 profile = profile->GetPrimaryOTRProfile();
363 }
364
365 if (!IsSilentLaunchEnabled(command_line, profile)) {
366 StartupBrowserCreatorImpl lwp(cur_dir, command_line, this, is_first_run);
367 const std::vector<GURL> urls_to_launch =
368 GetURLsFromCommandLine(command_line, cur_dir, profile);
369 const bool launched =
370 lwp.Launch(profile, urls_to_launch, in_synchronous_profile_launch_,
371 std::move(launch_mode_recorder));
372 in_synchronous_profile_launch_ = false;
373 if (!launched) {
374 LOG(ERROR) << "launch error";
375 return false;
376 }
377 } else {
378 in_synchronous_profile_launch_ = false;
379 }
380
381 profile_launch_observer.Get().AddLaunched(profile);
382
383 return true;
384 }
385
386 // static
WasRestarted()387 bool StartupBrowserCreator::WasRestarted() {
388 // Stores the value of the preference kWasRestarted had when it was read.
389 static bool was_restarted = false;
390
391 if (!was_restarted_read_) {
392 PrefService* pref_service = g_browser_process->local_state();
393 was_restarted = pref_service->GetBoolean(prefs::kWasRestarted);
394 pref_service->SetBoolean(prefs::kWasRestarted, false);
395 was_restarted_read_ = true;
396 }
397 return was_restarted;
398 }
399
400 // static
GetSessionStartupPref(const base::CommandLine & command_line,const Profile * profile)401 SessionStartupPref StartupBrowserCreator::GetSessionStartupPref(
402 const base::CommandLine& command_line,
403 const Profile* profile) {
404 DCHECK(profile);
405 const PrefService* prefs = profile->GetPrefs();
406 SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
407
408 // IsChromeFirstRun() looks for a sentinel file to determine whether the user
409 // is starting Chrome for the first time. On Chrome OS, the sentinel is stored
410 // in a location shared by all users and the check is meaningless. Query the
411 // UserManager instead to determine whether the user is new.
412 #if defined(OS_CHROMEOS)
413 const bool is_first_run =
414 user_manager::UserManager::Get()->IsCurrentUserNew();
415 // On ChromeOS restarts force the user to login again. The expectation is that
416 // after a login the user gets clean state. For this reason we ignore
417 // StartupBrowserCreator::WasRestarted(). However
418 // StartupBrowserCreator::WasRestarted has to be called in order to correctly
419 // update pref values.
420 const bool did_restart = false;
421 StartupBrowserCreator::WasRestarted();
422 #else
423 const bool is_first_run = first_run::IsChromeFirstRun();
424 const bool did_restart = StartupBrowserCreator::WasRestarted();
425 #endif
426
427 // The pref has an OS-dependent default value. For the first run only, this
428 // default is overridden with SessionStartupPref::DEFAULT so that first run
429 // behavior (sync promo, welcome page) is consistently invoked.
430 // This applies only if the pref is still at its default and has not been
431 // set by the user, managed prefs or policy.
432 if (is_first_run && SessionStartupPref::TypeIsDefault(prefs))
433 pref.type = SessionStartupPref::DEFAULT;
434
435 // The switches::kRestoreLastSession command line switch is used to restore
436 // sessions after a browser self restart (e.g. after a Chrome upgrade).
437 // However, new profiles can be created from a browser process that has this
438 // switch so do not set the session pref to SessionStartupPref::LAST for
439 // those as there is nothing to restore.
440 if ((command_line.HasSwitch(switches::kRestoreLastSession) || did_restart) &&
441 !profile->IsNewProfile()) {
442 pref.type = SessionStartupPref::LAST;
443 }
444
445 // A browser starting for a profile being unlocked should always restore.
446 if (!profile->IsGuestSession() && !profile->IsEphemeralGuestProfile()) {
447 ProfileAttributesEntry* entry = nullptr;
448 bool has_entry =
449 g_browser_process->profile_manager()
450 ->GetProfileAttributesStorage()
451 .GetProfileAttributesWithPath(profile->GetPath(), &entry);
452
453 if (has_entry && entry->IsSigninRequired())
454 pref.type = SessionStartupPref::LAST;
455 }
456
457 if (pref.type == SessionStartupPref::LAST && profile->IsOffTheRecord()) {
458 // We don't store session information when incognito. If the user has
459 // chosen to restore last session and launched incognito, fallback to
460 // default launch behavior.
461 pref.type = SessionStartupPref::DEFAULT;
462 }
463
464 return pref;
465 }
466
467 // static
ClearLaunchedProfilesForTesting()468 void StartupBrowserCreator::ClearLaunchedProfilesForTesting() {
469 profile_launch_observer.Get().Clear();
470 }
471
472 // static
RegisterLocalStatePrefs(PrefRegistrySimple * registry)473 void StartupBrowserCreator::RegisterLocalStatePrefs(
474 PrefRegistrySimple* registry) {
475 #if !defined(OS_CHROMEOS)
476 registry->RegisterBooleanPref(prefs::kPromotionalTabsEnabled, true);
477 registry->RegisterBooleanPref(prefs::kCommandLineFlagSecurityWarningsEnabled,
478 true);
479 #endif
480 registry->RegisterBooleanPref(prefs::kSuppressUnsupportedOSWarning, false);
481 registry->RegisterBooleanPref(prefs::kWasRestarted, false);
482
483 #if defined(OS_WIN)
484 registry->RegisterStringPref(prefs::kShortcutMigrationVersion, std::string());
485 #endif
486 }
487
488 // static
RegisterProfilePrefs(PrefRegistrySimple * registry)489 void StartupBrowserCreator::RegisterProfilePrefs(PrefRegistrySimple* registry) {
490 // Default to true so that existing users are not shown the Welcome page.
491 // ProfileManager handles setting this to false for new profiles upon
492 // creation.
493 registry->RegisterBooleanPref(prefs::kHasSeenWelcomePage, true);
494 #if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
495 // This will be set for newly created profiles, and is used to indicate which
496 // users went through onboarding with the current experiment group.
497 registry->RegisterStringPref(prefs::kNaviOnboardGroup, "");
498 #endif // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
499 }
500
501 // static
GetURLsFromCommandLine(const base::CommandLine & command_line,const base::FilePath & cur_dir,Profile * profile)502 std::vector<GURL> StartupBrowserCreator::GetURLsFromCommandLine(
503 const base::CommandLine& command_line,
504 const base::FilePath& cur_dir,
505 Profile* profile) {
506 DCHECK(profile);
507
508 std::vector<GURL> urls;
509
510 const base::CommandLine::StringVector& params = command_line.GetArgs();
511 for (size_t i = 0; i < params.size(); ++i) {
512 base::FilePath param = base::FilePath(params[i]);
513 // Handle Vista way of searching - "? <search-term>"
514 if ((param.value().size() > 2) && (param.value()[0] == '?') &&
515 (param.value()[1] == ' ')) {
516 GURL url(GetDefaultSearchURLForSearchTerms(
517 TemplateURLServiceFactory::GetForProfile(profile),
518 param.LossyDisplayName().substr(2)));
519 if (url.is_valid()) {
520 urls.push_back(url);
521 continue;
522 }
523 }
524
525 // Otherwise, fall through to treating it as a URL.
526
527 // This will create a file URL or a regular URL.
528 // This call can (in rare circumstances) block the UI thread.
529 // Allow it until this bug is fixed.
530 // http://code.google.com/p/chromium/issues/detail?id=60641
531 GURL url = GURL(param.MaybeAsASCII());
532
533 // http://crbug.com/371030: Only use URLFixerUpper if we don't have a valid
534 // URL, otherwise we will look in the current directory for a file named
535 // 'about' if the browser was started with a about:foo argument.
536 // http://crbug.com/424991: Always use URLFixerUpper on file:// URLs,
537 // otherwise we wouldn't correctly handle '#' in a file name.
538 if (!url.is_valid() || url.SchemeIsFile()) {
539 base::ThreadRestrictions::ScopedAllowIO allow_io;
540 url = url_formatter::FixupRelativeFile(cur_dir, param);
541 }
542 // Exclude dangerous schemes.
543 if (!url.is_valid())
544 continue;
545
546 const GURL settings_url = GURL(chrome::kChromeUISettingsURL);
547 bool url_points_to_an_approved_settings_page = false;
548 #if defined(OS_CHROMEOS)
549 // In ChromeOS, allow any settings page to be specified on the command line.
550 url_points_to_an_approved_settings_page =
551 url.GetOrigin() == settings_url.GetOrigin();
552 #else
553 // Exposed for external cleaners to offer a settings reset to the
554 // user. The allowed URLs must match exactly.
555 const GURL reset_settings_url =
556 settings_url.Resolve(chrome::kResetProfileSettingsSubPage);
557 url_points_to_an_approved_settings_page = url == reset_settings_url;
558 #if defined(OS_WIN)
559 // On Windows, also allow a hash for the Chrome Cleanup Tool.
560 const GURL reset_settings_url_with_cct_hash = reset_settings_url.Resolve(
561 std::string("#") +
562 settings::ResetSettingsHandler::kCctResetSettingsHash);
563 url_points_to_an_approved_settings_page =
564 url_points_to_an_approved_settings_page ||
565 url == reset_settings_url_with_cct_hash;
566 #endif // defined(OS_WIN)
567 #endif // defined(OS_CHROMEOS)
568
569 ChildProcessSecurityPolicy* policy =
570 ChildProcessSecurityPolicy::GetInstance();
571 if (policy->IsWebSafeScheme(url.scheme()) ||
572 url.SchemeIs(url::kFileScheme) ||
573 url_points_to_an_approved_settings_page ||
574 (url.spec().compare(url::kAboutBlankURL) == 0)) {
575 urls.push_back(url);
576 }
577 }
578 return urls;
579 }
580
ProcessCmdLineImpl(const base::CommandLine & command_line,const base::FilePath & cur_dir,bool process_startup,Profile * last_used_profile,const Profiles & last_opened_profiles)581 bool StartupBrowserCreator::ProcessCmdLineImpl(
582 const base::CommandLine& command_line,
583 const base::FilePath& cur_dir,
584 bool process_startup,
585 Profile* last_used_profile,
586 const Profiles& last_opened_profiles) {
587 DCHECK_CURRENTLY_ON(BrowserThread::UI);
588 TRACE_EVENT0("startup", "StartupBrowserCreator::ProcessCmdLineImpl");
589
590 DCHECK(last_used_profile);
591 if (process_startup &&
592 command_line.HasSwitch(switches::kDisablePromptOnRepost)) {
593 content::NavigationController::DisablePromptOnRepost();
594 }
595
596 bool silent_launch = false;
597 bool can_use_last_profile =
598 (CanOpenProfileOnStartup(last_used_profile) &&
599 !IncognitoModePrefs::ShouldLaunchIncognito(
600 command_line, last_used_profile->GetPrefs()));
601
602 #if defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
603 // If we are just displaying a print dialog we shouldn't open browser
604 // windows.
605 if (command_line.HasSwitch(switches::kCloudPrintFile) &&
606 can_use_last_profile &&
607 print_dialog_cloud::CreatePrintDialogFromCommandLine(last_used_profile,
608 command_line)) {
609 silent_launch = true;
610 }
611 #endif // defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
612
613 if (command_line.HasSwitch(switches::kValidateCrx)) {
614 if (!process_startup) {
615 LOG(ERROR) << "chrome is already running; you must close all running "
616 << "instances before running with the --"
617 << switches::kValidateCrx << " flag";
618 return false;
619 }
620 extensions::StartupHelper helper;
621 std::string message;
622 std::string error;
623 if (helper.ValidateCrx(command_line, &error))
624 message = std::string("ValidateCrx Success");
625 else
626 message = std::string("ValidateCrx Failure: ") + error;
627 printf("%s\n", message.c_str());
628 return false;
629 }
630
631 #if defined(OS_CHROMEOS)
632
633 // The browser will be launched after the user logs in.
634 if (command_line.HasSwitch(chromeos::switches::kLoginManager))
635 silent_launch = true;
636
637 if (chrome::IsRunningInForcedAppMode()) {
638 user_manager::User* user =
639 chromeos::ProfileHelper::Get()->GetUserByProfile(last_used_profile);
640 if (user && user->GetType() == user_manager::USER_TYPE_KIOSK_APP) {
641 chromeos::LaunchAppOrDie(
642 last_used_profile,
643 chromeos::KioskAppId::ForChromeApp(
644 command_line.GetSwitchValueASCII(switches::kAppId)));
645 } else if (user &&
646 user->GetType() == user_manager::USER_TYPE_WEB_KIOSK_APP) {
647 chromeos::LaunchAppOrDie(
648 last_used_profile,
649 chromeos::KioskAppId::ForWebApp(user->GetAccountId()));
650 } else {
651 // If we are here, we are either in ARC kiosk session or the user is
652 // invalid. We should terminate the session in such cases.
653 chrome::AttemptUserExit();
654 return false;
655 }
656
657 // Skip browser launch since app mode launches its app window.
658 silent_launch = true;
659 }
660
661 // If we are a demo app session and we crashed, there is no safe recovery
662 // possible. We should instead cleanly exit and go back to the OOBE screen,
663 // where we will launch again after the timeout has expired.
664 if (chromeos::DemoAppLauncher::IsDemoAppSession(
665 cryptohome::Identification::FromString(
666 command_line.GetSwitchValueASCII(chromeos::switches::kLoginUser))
667 .GetAccountId())) {
668 chrome::AttemptUserExit();
669 return false;
670 }
671 #endif // OS_CHROMEOS
672
673 #if defined(TOOLKIT_VIEWS) && defined(USE_X11)
674 if (!features::IsUsingOzonePlatform()) {
675 // Ozone sets the device list upon platform initialisation.
676 ui::TouchFactory::SetTouchDeviceListFromCommandLine();
677 }
678 #endif
679
680 #if defined(OS_MAC)
681 if (web_app::MaybeRebuildShortcut(command_line))
682 return true;
683 #endif
684
685 if (!process_startup &&
686 command_line.HasSwitch(switches::kDumpBrowserHistograms)) {
687 // Only handle --dump-browser-histograms from a rendezvous. In this case, do
688 // not open a new browser window even if no output file was given.
689 base::FilePath output_file(
690 command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
691 if (!output_file.empty()) {
692 base::ThreadPool::PostTask(
693 FROM_HERE,
694 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
695 base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
696 base::BindOnce(&DumpBrowserHistograms, output_file));
697 }
698 silent_launch = true;
699 }
700
701 #if !defined(OS_CHROMEOS)
702 if (base::FeatureList::IsEnabled(features::kOnConnectNative) &&
703 command_line.HasSwitch(switches::kNativeMessagingConnectHost) &&
704 command_line.HasSwitch(switches::kNativeMessagingConnectExtension)) {
705 extensions::LaunchNativeMessageHostFromNativeApp(
706 command_line.GetSwitchValueASCII(
707 switches::kNativeMessagingConnectExtension),
708 command_line.GetSwitchValueASCII(switches::kNativeMessagingConnectHost),
709 command_line.GetSwitchValueASCII(switches::kNativeMessagingConnectId),
710 last_used_profile);
711
712 // Chrome's lifetime, if the specified extension and native messaging host
713 // are both valid and a connection is established, is prolonged by
714 // BackgroundModeManager. If |process_startup| is true, --no-startup-window
715 // must be set or a browser window must be created for BackgroundModeManager
716 // to start background mode. Without this, nothing will take the first
717 // keep-alive and the browser process will not terminate. To avoid this
718 // situation, don't set |silent_launch| in response to the native messaging
719 // connect switches; require the client to pass --no-startup-window if
720 // suppressing the creation of a window is desired.
721 }
722 #endif
723
724 // If --no-startup-window is specified and Chrome is already running then do
725 // not open a new window.
726 if (!process_startup && command_line.HasSwitch(switches::kNoStartupWindow))
727 silent_launch = true;
728
729 // If we don't want to launch a new browser window or tab we are done here.
730 if (silent_launch) {
731 if (process_startup)
732 startup_metric_utils::SetNonBrowserUIDisplayed();
733 return true;
734 }
735
736 if (command_line.HasSwitch(extensions::switches::kLoadApps) &&
737 can_use_last_profile) {
738 if (!ProcessLoadApps(command_line, cur_dir, last_used_profile))
739 return false;
740
741 // Return early here to avoid opening a browser window.
742 // The exception is when there are no browser windows, since we don't want
743 // chrome to shut down.
744 // TODO(jackhou): Do this properly once keep-alive is handled by the
745 // background page of apps. Tracked at http://crbug.com/175381
746 if (chrome::GetBrowserCount(last_used_profile) != 0)
747 return true;
748 }
749
750 // Check for --load-and-launch-app.
751 if (command_line.HasSwitch(apps::kLoadAndLaunchApp) && can_use_last_profile) {
752 base::CommandLine::StringType path =
753 command_line.GetSwitchValueNative(apps::kLoadAndLaunchApp);
754
755 if (!apps::AppLoadService::Get(last_used_profile)
756 ->LoadAndLaunch(base::FilePath(path), command_line, cur_dir)) {
757 return false;
758 }
759
760 // Return early here since we don't want to open a browser window.
761 // The exception is when there are no browser windows, since we don't want
762 // chrome to shut down.
763 // TODO(jackhou): Do this properly once keep-alive is handled by the
764 // background page of apps. Tracked at http://crbug.com/175381
765 if (chrome::GetBrowserCount(last_used_profile) != 0)
766 return true;
767 }
768
769 #if defined(OS_WIN)
770 // Log whether this process was a result of an action in the Windows Jumplist.
771 if (command_line.HasSwitch(switches::kWinJumplistAction)) {
772 jumplist::LogJumplistActionFromSwitchValue(
773 command_line.GetSwitchValueASCII(switches::kWinJumplistAction));
774 // Use a non-NULL pointer to indicate JumpList has been used. We re-use
775 // chrome::kJumpListIconDirname as the key to the data.
776 last_used_profile->SetUserData(
777 chrome::kJumpListIconDirname,
778 base::WrapUnique(new base::SupportsUserData::Data()));
779 }
780
781 // If the command line has the kNotificationLaunchId switch, then this
782 // call is from notification_helper.exe to process toast activation.
783 // Delegate to the notification system; do not open a browser window here.
784 if (command_line.HasSwitch(switches::kNotificationLaunchId)) {
785 if (NotificationPlatformBridgeWin::HandleActivation(command_line)) {
786 LaunchModeRecorder().SetLaunchMode(LaunchMode::kWinPlatformNotification);
787 return true;
788 }
789 return false;
790 }
791
792 // If being started for credential provider logon purpose, only show the
793 // signin page.
794 if (command_line.HasSwitch(credential_provider::kGcpwSigninSwitch)) {
795 // Use incognito profile since this is a credential provider logon.
796 Profile* profile = last_used_profile->GetPrimaryOTRProfile();
797 DCHECK(profile->IsIncognitoProfile());
798 // NOTE: All launch urls are ignored when running with --gcpw-signin since
799 // this mode only loads Google's sign in page.
800
801 // If GCPW signin dialog fails, returning false here will allow Chrome to
802 // exit gracefully during the launch.
803 if (!StartGCPWSignin(command_line, profile))
804 return false;
805
806 LaunchModeRecorder().SetLaunchMode(LaunchMode::kCredentialProviderSignIn);
807 return true;
808 }
809 #endif // defined(OS_WIN)
810
811 return LaunchBrowserForLastProfiles(command_line, cur_dir, process_startup,
812 last_used_profile, last_opened_profiles);
813 }
814
LaunchBrowserForLastProfiles(const base::CommandLine & command_line,const base::FilePath & cur_dir,bool process_startup,Profile * last_used_profile,const Profiles & last_opened_profiles)815 bool StartupBrowserCreator::LaunchBrowserForLastProfiles(
816 const base::CommandLine& command_line,
817 const base::FilePath& cur_dir,
818 bool process_startup,
819 Profile* last_used_profile,
820 const Profiles& last_opened_profiles) {
821 #if !defined(OS_CHROMEOS)
822 const std::vector<GURL> urls_to_launch =
823 StartupBrowserCreator::GetURLsFromCommandLine(command_line, cur_dir,
824 last_used_profile);
825 if (ProfilePicker::ShouldShowAtLaunch(command_line, urls_to_launch)) {
826 ProfilePicker::Show(
827 process_startup
828 ? ProfilePicker::EntryPoint::kOnStartup
829 : ProfilePicker::EntryPoint::kNewSessionOnExistingProcess);
830 return true;
831 }
832 #endif // !defined(OS_CHROMEOS)
833
834 chrome::startup::IsProcessStartup is_process_startup =
835 process_startup ? chrome::startup::IS_PROCESS_STARTUP
836 : chrome::startup::IS_NOT_PROCESS_STARTUP;
837 chrome::startup::IsFirstRun is_first_run =
838 first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN
839 : chrome::startup::IS_NOT_FIRST_RUN;
840
841 // On Windows, when chrome is launched by notification activation where the
842 // kNotificationLaunchId switch is used, always use |last_used_profile| which
843 // contains the profile id extracted from the notification launch id.
844 bool was_windows_notification_launch = false;
845 #if defined(OS_WIN)
846 was_windows_notification_launch =
847 command_line.HasSwitch(switches::kNotificationLaunchId);
848 #endif // defined(OS_WIN)
849
850 // |last_opened_profiles| will be empty in the following circumstances:
851 // - This is the first launch. |last_used_profile| is the initial profile.
852 // - The user exited the browser by closing all windows for all profiles.
853 // |last_used_profile| is the profile which owned the last open window.
854 // - Only incognito windows were open when the browser exited.
855 // |last_used_profile| is the last used incognito profile. Restoring it will
856 // create a browser window for the corresponding original profile.
857 // - All of the last opened profiles fail to initialize.
858 if (last_opened_profiles.empty() || was_windows_notification_launch) {
859 if (CanOpenProfileOnStartup(last_used_profile)) {
860 Profile* profile_to_open = last_used_profile->IsGuestSession()
861 ? last_used_profile->GetPrimaryOTRProfile()
862 : last_used_profile;
863 return LaunchBrowser(command_line, profile_to_open, cur_dir,
864 is_process_startup, is_first_run,
865 std::make_unique<LaunchModeRecorder>());
866 }
867
868 // Show UserManager if |last_used_profile| can't be auto opened.
869 ShowUserManagerOnStartup();
870 return true;
871 }
872 return ProcessLastOpenedProfiles(command_line, cur_dir, is_process_startup,
873 is_first_run, last_used_profile,
874 last_opened_profiles);
875 }
876
ProcessLastOpenedProfiles(const base::CommandLine & command_line,const base::FilePath & cur_dir,chrome::startup::IsProcessStartup is_process_startup,chrome::startup::IsFirstRun is_first_run,Profile * last_used_profile,const Profiles & last_opened_profiles)877 bool StartupBrowserCreator::ProcessLastOpenedProfiles(
878 const base::CommandLine& command_line,
879 const base::FilePath& cur_dir,
880 chrome::startup::IsProcessStartup is_process_startup,
881 chrome::startup::IsFirstRun is_first_run,
882 Profile* last_used_profile,
883 const Profiles& last_opened_profiles) {
884 base::CommandLine command_line_without_urls(command_line.GetProgram());
885 for (auto& switch_pair : command_line.GetSwitches()) {
886 command_line_without_urls.AppendSwitchNative(switch_pair.first,
887 switch_pair.second);
888 }
889
890 // Launch the profiles in the order they became active.
891 for (Profile* profile : last_opened_profiles) {
892 DCHECK(!profile->IsGuestSession() && !profile->IsEphemeralGuestProfile());
893
894 #if !defined(OS_CHROMEOS)
895 // Skip any locked profile.
896 if (!CanOpenProfileOnStartup(profile))
897 continue;
898
899 // Guest profiles should not be reopened on startup. This can happen if
900 // the last used profile was a Guest, but other profiles were also open
901 // when Chrome was closed. In this case, pick a different open profile
902 // to be the active one, since the Guest profile is never added to the
903 // list of open profiles.
904 if (last_used_profile->IsGuestSession() ||
905 last_used_profile->IsEphemeralGuestProfile()) {
906 last_used_profile = profile;
907 }
908 #endif
909
910 // Don't launch additional profiles which would only open a new tab
911 // page. When restarting after an update, all profiles will reopen last
912 // open pages.
913 SessionStartupPref startup_pref =
914 GetSessionStartupPref(command_line, profile);
915 if (profile != last_used_profile &&
916 startup_pref.type == SessionStartupPref::DEFAULT &&
917 !HasPendingUncleanExit(profile)) {
918 continue;
919 }
920 // Only record a launch mode histogram for |last_used_profile|. Pass a
921 // null launch_mode_recorder for other profiles.
922 if (!LaunchBrowser((profile == last_used_profile)
923 ? command_line
924 : command_line_without_urls,
925 profile, cur_dir, is_process_startup, is_first_run,
926 profile == last_used_profile
927 ? std::make_unique<LaunchModeRecorder>()
928 : nullptr)) {
929 return false;
930 }
931 // We've launched at least one browser.
932 is_process_startup = chrome::startup::IS_NOT_PROCESS_STARTUP;
933 }
934
935 // Set the |last_used_profile| to activate if a browser is launched for at
936 // least one profile. Otherwise, show UserManager.
937 // Note that this must be done after all profiles have
938 // been launched so the observer knows about all profiles to wait before
939 // activation this one.
940 #if !defined(OS_CHROMEOS)
941 if (is_process_startup == chrome::startup::IS_PROCESS_STARTUP)
942 ShowUserManagerOnStartup();
943 else
944 #endif
945 profile_launch_observer.Get().set_profile_to_activate(last_used_profile);
946 return true;
947 }
948
949 // static
ProcessLoadApps(const base::CommandLine & command_line,const base::FilePath & cur_dir,Profile * profile)950 bool StartupBrowserCreator::ProcessLoadApps(
951 const base::CommandLine& command_line,
952 const base::FilePath& cur_dir,
953 Profile* profile) {
954 base::CommandLine::StringType path_list =
955 command_line.GetSwitchValueNative(extensions::switches::kLoadApps);
956
957 base::StringTokenizerT<base::CommandLine::StringType,
958 base::CommandLine::StringType::const_iterator>
959 tokenizer(path_list, FILE_PATH_LITERAL(","));
960
961 if (!tokenizer.GetNext())
962 return false;
963
964 base::FilePath app_absolute_dir =
965 base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token()));
966 if (!apps::AppLoadService::Get(profile)->LoadAndLaunch(
967 app_absolute_dir, command_line, cur_dir)) {
968 return false;
969 }
970
971 while (tokenizer.GetNext()) {
972 app_absolute_dir =
973 base::MakeAbsoluteFilePath(base::FilePath(tokenizer.token()));
974
975 if (!apps::AppLoadService::Get(profile)->Load(app_absolute_dir)) {
976 return false;
977 }
978 }
979
980 return true;
981 }
982
983 // static
ProcessCommandLineOnProfileCreated(const base::CommandLine & command_line,const base::FilePath & cur_dir,Profile * profile,Profile::CreateStatus status)984 void StartupBrowserCreator::ProcessCommandLineOnProfileCreated(
985 const base::CommandLine& command_line,
986 const base::FilePath& cur_dir,
987 Profile* profile,
988 Profile::CreateStatus status) {
989 if (status != Profile::CREATE_STATUS_INITIALIZED)
990 return;
991 StartupBrowserCreator startup_browser_creator;
992 startup_browser_creator.ProcessCmdLineImpl(command_line, cur_dir, false,
993 profile, Profiles());
994 }
995
996 // static
ProcessCommandLineAlreadyRunning(const base::CommandLine & command_line,const base::FilePath & cur_dir,const base::FilePath & profile_path)997 void StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
998 const base::CommandLine& command_line,
999 const base::FilePath& cur_dir,
1000 const base::FilePath& profile_path) {
1001 ProfileManager* profile_manager = g_browser_process->profile_manager();
1002 Profile* profile = profile_manager->GetProfileByPath(profile_path);
1003
1004 // The profile isn't loaded yet and so needs to be loaded asynchronously.
1005 if (!profile) {
1006 profile_manager->CreateProfileAsync(
1007 profile_path,
1008 base::BindRepeating(&ProcessCommandLineOnProfileCreated, command_line,
1009 cur_dir),
1010 base::string16(), std::string());
1011 return;
1012 }
1013 StartupBrowserCreator startup_browser_creator;
1014 Profiles last_opened_profiles;
1015 #if !defined(OS_CHROMEOS)
1016 // On ChromeOS multiple profiles doesn't apply.
1017 // If no browser windows are open, i.e. the browser is being kept alive in
1018 // background mode or for other processing, restore |last_opened_profiles|.
1019 if (chrome::GetTotalBrowserCount() == 0)
1020 last_opened_profiles = profile_manager->GetLastOpenedProfiles();
1021 #endif // defined(OS_CHROMEOS)
1022 startup_browser_creator.ProcessCmdLineImpl(command_line, cur_dir,
1023 /*process_startup=*/false, profile,
1024 last_opened_profiles);
1025 }
1026
1027 // static
OpenStartupPages(Browser * browser,bool process_startup)1028 void StartupBrowserCreator::OpenStartupPages(Browser* browser,
1029 bool process_startup) {
1030 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
1031 chrome::startup::IsFirstRun is_first_run =
1032 first_run::IsChromeFirstRun() ? chrome::startup::IS_FIRST_RUN
1033 : chrome::startup::IS_NOT_FIRST_RUN;
1034 StartupBrowserCreatorImpl startup_browser_creator_impl(
1035 base::FilePath(), command_line, is_first_run);
1036 SessionStartupPref session_startup_pref =
1037 StartupBrowserCreator::GetSessionStartupPref(command_line,
1038 browser->profile());
1039 startup_browser_creator_impl.OpenURLsInBrowser(browser, process_startup,
1040 session_startup_pref.urls);
1041 }
1042
1043 // static
ActivatedProfile()1044 bool StartupBrowserCreator::ActivatedProfile() {
1045 return profile_launch_observer.Get().activated_profile();
1046 }
1047
HasPendingUncleanExit(Profile * profile)1048 bool HasPendingUncleanExit(Profile* profile) {
1049 return profile->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
1050 !profile_launch_observer.Get().HasBeenLaunched(profile);
1051 }
1052
GetStartupProfilePath(const base::FilePath & user_data_dir,const base::CommandLine & command_line)1053 base::FilePath GetStartupProfilePath(const base::FilePath& user_data_dir,
1054 const base::CommandLine& command_line) {
1055 // If the browser is launched due to activation on Windows native notification,
1056 // the profile id encoded in the notification launch id should be chosen over
1057 // all others.
1058 #if defined(OS_WIN)
1059 std::string profile_id =
1060 NotificationLaunchId::GetNotificationLaunchProfileId(command_line);
1061 if (!profile_id.empty()) {
1062 return user_data_dir.Append(base::FilePath(base::UTF8ToUTF16(profile_id)));
1063 }
1064 #endif // defined(OS_WIN)
1065
1066 // If opening in Guest mode is requested, load the default profile so that
1067 // last opened profile would not trigger a user management dialog.
1068 if (profiles::IsGuestModeRequested(command_line,
1069 g_browser_process->local_state(),
1070 /* show_warning= */ false)) {
1071 return profiles::GetDefaultProfileDir(user_data_dir);
1072 }
1073
1074 if (command_line.HasSwitch(switches::kProfileDirectory)) {
1075 return user_data_dir.Append(
1076 command_line.GetSwitchValuePath(switches::kProfileDirectory));
1077 }
1078
1079 return g_browser_process->profile_manager()->GetLastUsedProfileDir(
1080 user_data_dir);
1081 }
1082
1083 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
GetStartupProfile(const base::FilePath & user_data_dir,const base::CommandLine & command_line)1084 Profile* GetStartupProfile(const base::FilePath& user_data_dir,
1085 const base::CommandLine& command_line) {
1086 ProfileManager* profile_manager = g_browser_process->profile_manager();
1087
1088 base::FilePath profile_path =
1089 GetStartupProfilePath(user_data_dir, command_line);
1090 Profile* profile = profile_manager->GetProfile(profile_path);
1091
1092 // If there is no entry in profile attributes storage, the profile is deleted,
1093 // and we should show the user manager. Also, when using
1094 // --new-profile-management, if the profile is locked we should show the user
1095 // manager as well. When neither of these is true, we can safely start up with
1096 // |profile|.
1097 auto* storage = &profile_manager->GetProfileAttributesStorage();
1098 ProfileAttributesEntry* entry;
1099 bool has_entry = storage->GetProfileAttributesWithPath(profile_path, &entry);
1100 if (has_entry && (!entry->IsSigninRequired() || !profile)) {
1101 return profile;
1102 }
1103
1104 // We want to show the user manager. To indicate this, return the guest
1105 // profile. However, we can only do this if the system profile (where the user
1106 // manager lives) also exists (or is creatable).
1107 return profile_manager->GetProfile(ProfileManager::GetSystemProfilePath())
1108 ? profile_manager->GetProfile(
1109 ProfileManager::GetGuestProfilePath())
1110 : nullptr;
1111 }
1112
GetFallbackStartupProfile()1113 Profile* GetFallbackStartupProfile() {
1114 ProfileManager* profile_manager = g_browser_process->profile_manager();
1115 // The only known reason for profiles to fail initialization is being unable
1116 // to create the profile directory, and this has already happened in
1117 // GetStartupProfilePath() before calling this function. In this case,
1118 // creation of new profiles is expected to fail. So only existing profiles are
1119 // attempted for fallback.
1120
1121 // If the last used profile could not be initialized, see if any of other last
1122 // opened profiles can be initialized successfully.
1123 auto* storage = &profile_manager->GetProfileAttributesStorage();
1124 for (Profile* profile : ProfileManager::GetLastOpenedProfiles()) {
1125 // Return any profile that is not locked.
1126 ProfileAttributesEntry* entry;
1127 bool has_entry =
1128 storage->GetProfileAttributesWithPath(profile->GetPath(), &entry);
1129 if (!has_entry || !entry->IsSigninRequired())
1130 return profile;
1131 }
1132
1133 // Couldn't initialize any last opened profiles. Try to show the user manager,
1134 // which requires successful initialization of the guest and system profiles.
1135 Profile* guest_profile =
1136 profile_manager->GetProfile(ProfileManager::GetGuestProfilePath());
1137 Profile* system_profile =
1138 profile_manager->GetProfile(ProfileManager::GetSystemProfilePath());
1139 if (guest_profile && system_profile)
1140 return guest_profile;
1141
1142 // Couldn't show the user manager either. Try to open any profile that is not
1143 // locked.
1144 for (ProfileAttributesEntry* entry : storage->GetAllProfilesAttributes()) {
1145 if (!entry->IsSigninRequired()) {
1146 Profile* profile = profile_manager->GetProfile(entry->GetPath());
1147 if (profile)
1148 return profile;
1149 }
1150 }
1151
1152 return nullptr;
1153 }
1154 #endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
1155