blob: eee0ccf1b6dd897158b7ebb993bc3863d21f83c6 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
#include <stddef.h>
#include <algorithm>
#include <iterator>
#include <memory>
#include <utility>
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/debug/dump_without_crashing.h"
#include "base/functional/bind.h"
#include "base/notreached.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/apps/platform_apps/install_chrome_app.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/first_run/first_run.h"
#include "chrome/browser/headless/headless_command_processor.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_service_factory.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/signin/account_consistency_mode_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
#include "chrome/browser/ui/startup/infobar_utils.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "chrome/browser/ui/startup/startup_tab.h"
#include "chrome/browser/ui/startup/startup_tab_provider.h"
#include "chrome/browser/ui/startup/startup_types.h"
#include "chrome/browser/ui/tabs/shared_tab_group_version_upgrade_modal.h"
#include "chrome/browser/ui/toasts/api/toast_id.h"
#include "chrome/browser/ui/toasts/toast_controller.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/webui/whats_new/whats_new_util.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "components/custom_handlers/protocol_handler_registry.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/privacy_sandbox_features.h"
#include "components/signin/public/base/signin_switches.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_switches.h"
#if BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#include "chrome/browser/app_controller_mac.h"
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(ENABLE_RLZ)
#include "components/google/core/common/google_util.h"
#include "components/rlz/rlz_tracker.h" // nogncheck
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "components/app_restore/full_restore_utils.h"
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
#include "chrome/browser/ui/webui/whats_new/whats_new_fetcher.h"
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
namespace {
// Utility functions ----------------------------------------------------------
// On ChromeOS Ash check the previous apps launching history info to decide
// whether restore apps.
//
// In other platforms, restore apps only when the browser is automatically
// restarted.
bool ShouldRestoreApps(bool is_post_restart, Profile* profile) {
#if BUILDFLAG(IS_CHROMEOS)
// In ChromeOS, restore apps only when there are apps launched before reboot.
return full_restore::HasAppTypeBrowser(profile->GetPath());
#else
return is_post_restart;
#endif
}
void UrlsToTabs(const std::vector<GURL>& urls, StartupTabs* tabs) {
for (const GURL& url : urls) {
tabs->emplace_back(url);
}
}
// Appends the contents of |from| to the end of |to|.
void AppendTabs(const StartupTabs& from, StartupTabs* to) {
to->insert(to->end(), from.begin(), from.end());
}
// Prepends the contents of |from| to the beginning of |to|.
void PrependTabs(const StartupTabs& from, StartupTabs* to) {
to->insert(to->begin(), from.begin(), from.end());
}
} // namespace
StartupBrowserCreatorImpl::StartupBrowserCreatorImpl(
const base::FilePath& cur_dir,
const base::CommandLine& command_line,
chrome::startup::IsFirstRun is_first_run)
: cur_dir_(cur_dir),
command_line_(command_line),
profile_(nullptr),
browser_creator_(nullptr),
is_first_run_(is_first_run) {}
StartupBrowserCreatorImpl::StartupBrowserCreatorImpl(
const base::FilePath& cur_dir,
const base::CommandLine& command_line,
StartupBrowserCreator* browser_creator,
chrome::startup::IsFirstRun is_first_run)
: cur_dir_(cur_dir),
command_line_(command_line),
browser_creator_(browser_creator),
is_first_run_(is_first_run) {}
StartupBrowserCreatorImpl::~StartupBrowserCreatorImpl() = default;
// static
void StartupBrowserCreatorImpl::MaybeToggleFullscreen(
BrowserWindowInterface* browser) {
// In kiosk mode, we want to always be fullscreen.
if (IsKioskModeEnabled() || base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kStartFullscreen)) {
chrome::ToggleFullscreenMode(browser, /*user_initiated=*/false);
}
}
void StartupBrowserCreatorImpl::Launch(
Profile* profile,
chrome::startup::IsProcessStartup process_startup,
bool restore_tabbed_browser) {
DCHECK(profile);
profile_ = profile;
DetermineURLsAndLaunch(process_startup, restore_tabbed_browser);
// It's possible for there to be no browser window, e.g. if someone
// specified a non-sensical combination of options
// ("--kiosk --no_startup_window"); do nothing in that case.
BrowserWindowInterface* const browser =
GetLastActiveBrowserWindowInterfaceWithAnyProfile();
if (!browser) {
LOG(ERROR) << "No browser window found for startup.";
return;
}
if (command_line_->HasSwitch(switches::kInstallChromeApp)) {
install_chrome_app::InstallChromeApp(
command_line_->GetSwitchValueASCII(switches::kInstallChromeApp),
browser);
}
MaybeToggleFullscreen(browser);
}
Browser* StartupBrowserCreatorImpl::OpenURLsInBrowser(
Browser* browser,
chrome::startup::IsProcessStartup process_startup,
const std::vector<GURL>& urls) {
StartupTabs tabs;
UrlsToTabs(urls, &tabs);
return OpenTabsInBrowser(browser, process_startup, tabs, TabOverWrite::kNo);
}
Browser* StartupBrowserCreatorImpl::OpenTabsInBrowser(
Browser* browser,
chrome::startup::IsProcessStartup process_startup,
const StartupTabs& tabs,
TabOverWrite is_active_tab_overwrite) {
DCHECK(!tabs.empty());
// If we don't yet have a profile, try to use the one we're given from
// |browser|. While we may not end up actually using |browser| (since it
// could be a popup window), we can at least use the profile.
if (!profile_ && browser) {
profile_ = browser->profile();
}
if (!browser || !browser->is_type_normal()) {
CHECK(profile_);
// In some conditions a new browser object cannot be created. The most
// common reason for not being able to create browser is having this call
// when the browser process is shutting down. This can also fail if the
// passed profile is of a type that is not suitable for browser creation.
if (Browser::GetCreationStatusForProfile(profile_) !=
Browser::CreationStatus::kOk) {
return nullptr;
}
// Startup browsers are not counted as being created by a user_gesture
// because of historical accident, even though the startup browser was
// created in response to the user clicking on chrome. There was an
// incomplete check on whether a user gesture created a window which looked
// at the state of the MessageLoop.
Browser::CreateParams params = Browser::CreateParams(profile_, false);
params.creation_source = Browser::CreationSource::kStartupCreator;
#if BUILDFLAG(IS_LINUX)
params.startup_id =
command_line_->GetSwitchValueASCII("desktop-startup-id");
#endif
if (command_line_->HasSwitch(switches::kWindowName)) {
params.user_title =
command_line_->GetSwitchValueASCII(switches::kWindowName);
}
browser = Browser::Create(params);
}
CHECK(profile_);
bool first_tab = true;
bool process_headless_commands = headless::ShouldProcessHeadlessCommands();
custom_handlers::ProtocolHandlerRegistry* registry =
ProtocolHandlerRegistryFactory::GetForBrowserContext(profile_);
for (auto& tab : tabs) {
// We skip URLs that we'd have to launch an external protocol handler for.
// This avoids us getting into an infinite loop asking ourselves to open
// a URL, should the handler be (incorrectly) configured to be us. Anyone
// asking us to open such a URL should really ask the handler directly.
bool handled_by_chrome =
ProfileIOData::IsHandledURL(tab.url) ||
(registry && registry->IsHandledProtocol(tab.url.GetScheme()));
if (process_startup == chrome::startup::IsProcessStartup::kNo &&
!handled_by_chrome) {
continue;
}
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
// Start the What's New fetch but don't add the tab at this point. The tab
// will open as the foreground tab only if the remote content can be
// retrieved successfully. This prevents needing to automatically close the
// tab after opening it in the case where What's New does not load.
if (tab.url == whats_new::GetWebUIStartupURL()) {
whats_new::StartWhatsNewFetch(browser);
continue;
}
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
// Headless mode is restricted to only one url in the command line, so
// just grab the first one assuming it's the target.
if (first_tab && process_headless_commands) {
std::unique_ptr<ScopedProfileKeepAlive> profile_keepalive;
if (!profile_->IsOffTheRecord()) {
profile_keepalive = std::make_unique<ScopedProfileKeepAlive>(
profile_, ProfileKeepAliveOrigin::kHeadlessCommand);
}
headless::ProcessHeadlessCommands(
profile_, tab.url,
base::BindOnce(
[](base::WeakPtr<Browser> browser,
std::unique_ptr<ScopedProfileKeepAlive> profile_keepalive,
headless::HeadlessCommandHandler::Result result) {
if (browser && browser->window()) {
#if BUILDFLAG(IS_MAC)
// On Macs Chrome keeps running after the last browser
// window is closed which is not expected for headless
// command execution, so explicitly allow application
// to terminate after the browser window is closed.
app_controller_mac::AllowApplicationToTerminate();
#endif
browser->window()->Close();
}
},
browser->AsWeakPtr(), std::move(profile_keepalive)));
continue;
}
// Active tab overwrites apply only to one tab per launch, and can only
// happen if there is already a tab open to replace
if (first_tab && browser->tab_strip_model()->count() &&
(is_active_tab_overwrite == TabOverWrite::kYes)) {
NavigateParams params(browser, tab.url,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
params.disposition = WindowOpenDisposition::CURRENT_TAB;
params.tabstrip_add_types = ADD_NONE;
first_tab = false;
Navigate(&params);
continue;
}
int add_types = first_tab ? AddTabTypes::ADD_ACTIVE : AddTabTypes::ADD_NONE;
add_types |= AddTabTypes::ADD_FORCE_INDEX;
if (tab.type == StartupTab::Type::kPinned) {
add_types |= AddTabTypes::ADD_PINNED;
}
NavigateParams params(browser, tab.url, ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
params.disposition = first_tab ? WindowOpenDisposition::NEW_FOREGROUND_TAB
: WindowOpenDisposition::NEW_BACKGROUND_TAB;
params.tabstrip_add_types = add_types;
#if BUILDFLAG(ENABLE_RLZ)
if (process_startup == chrome::startup::IsProcessStartup::kYes &&
google_util::IsGoogleHomePageUrl(tab.url)) {
params.extra_headers = rlz::RLZTracker::GetAccessPointHttpHeader(
rlz::RLZTracker::ChromeHomePage());
}
#endif // BUILDFLAG(ENABLE_RLZ)
Navigate(&params);
first_tab = false;
}
if (!browser->tab_strip_model()->GetActiveWebContents() &&
!process_headless_commands) {
// TODO(sky): this is a work around for 110909. Figure out why it's needed.
if (!browser->tab_strip_model()->count()) {
chrome::AddTabAt(browser, GURL(), -1, true);
} else {
browser->tab_strip_model()->ActivateTabAt(0);
}
}
browser->window()->Show();
return browser;
}
void StartupBrowserCreatorImpl::DetermineURLsAndLaunch(
chrome::startup::IsProcessStartup process_startup,
bool restore_tabbed_browser) {
if (StartupBrowserCreator::ShouldLoadProfileWithoutWindow(*command_line_)) {
// Checking the flags this late in the launch should be redundant.
// TODO(crbug.com/40216113): Remove by M104.
NOTREACHED();
}
const bool is_incognito_or_guest = profile_->IsOffTheRecord();
bool is_post_crash_launch = HasPendingUncleanExit(profile_);
// Presentation of promotional and/or educational tabs may be controlled via
// administrative policy.
bool promotions_enabled = true;
const PrefService::Preference* promotions_enabled_pref = nullptr;
PrefService* local_state = g_browser_process->local_state();
if (local_state) {
promotions_enabled_pref =
local_state->FindPreference(prefs::kPromotionsEnabled);
}
if (promotions_enabled_pref && promotions_enabled_pref->IsManaged()) {
// Presentation is managed; obey the policy setting.
promotions_enabled = promotions_enabled_pref->GetValue()->GetBool();
} else {
// Presentation is not managed. Infer an intent to disable if any value for
// the RestoreOnStartup policy is mandatory or recommended.
promotions_enabled =
!SessionStartupPref::TypeIsManaged(profile_->GetPrefs()) &&
!SessionStartupPref::TypeHasRecommendedValue(profile_->GetPrefs());
}
const bool whats_new_enabled =
whats_new::ShouldShowForState(local_state, promotions_enabled);
auto* privacy_sandbox_service =
PrivacySandboxServiceFactory::GetForProfile(profile_);
bool privacy_sandbox_dialog_required = false;
if (privacy_sandbox_service) {
switch (privacy_sandbox_service->GetRequiredPromptType(
PrivacySandboxService::SurfaceType::kDesktop)) {
case PrivacySandboxService::PromptType::kM1Consent:
case PrivacySandboxService::PromptType::kM1NoticeEEA:
case PrivacySandboxService::PromptType::kM1NoticeROW:
case PrivacySandboxService::PromptType::kM1NoticeRestricted:
privacy_sandbox_dialog_required = true;
break;
case PrivacySandboxService::PromptType::kNone:
break;
}
}
auto result = DetermineStartupTabs(
StartupTabProviderImpl(), process_startup, is_incognito_or_guest,
is_post_crash_launch, promotions_enabled, whats_new_enabled,
privacy_sandbox_dialog_required);
StartupTabs tabs = std::move(result.tabs);
// Return immediately if we start an async restore, since the remainder of
// that process is self-contained.
if (MaybeAsyncRestore(tabs, process_startup, is_post_crash_launch)) {
return;
}
BrowserOpenBehaviorOptions behavior_options = 0;
if (process_startup == chrome::startup::IsProcessStartup::kYes) {
behavior_options |= PROCESS_STARTUP;
}
if (is_post_crash_launch) {
behavior_options |= IS_POST_CRASH_LAUNCH;
}
if (command_line_->HasSwitch(switches::kOpenInNewWindow)) {
behavior_options |= HAS_NEW_WINDOW_SWITCH;
}
if (command_line_->HasSwitch(switches::kSameTab)) {
behavior_options |= HAS_SAME_TAB_SWITCH;
}
if (result.launch_result == LaunchResult::kWithGivenUrls) {
behavior_options |= HAS_CMD_LINE_TABS;
}
BrowserOpenBehavior behavior = DetermineBrowserOpenBehavior(
StartupBrowserCreator::GetSessionStartupPref(*command_line_, profile_),
behavior_options);
SessionRestore::BehaviorBitmask restore_options =
restore_tabbed_browser ? SessionRestore::RESTORE_BROWSER : 0;
if (behavior == BrowserOpenBehavior::SYNCHRONOUS_RESTORE) {
#if BUILDFLAG(IS_MAC)
bool was_mac_login_or_resume = base::mac::WasLaunchedAsLoginOrResumeItem();
#else
bool was_mac_login_or_resume = false;
#endif
restore_options = DetermineSynchronousRestoreOptions(
browser_defaults::kAlwaysCreateTabbedBrowserOnSessionRestore,
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kCreateBrowserOnStartupForTests),
was_mac_login_or_resume, restore_tabbed_browser);
}
Browser* browser = RestoreOrCreateBrowser(
tabs, behavior, restore_options, process_startup, is_post_crash_launch);
// Finally, add info bars.
AddInfoBarsIfNecessary(browser, profile_, *command_line_, is_first_run_,
/*is_web_app=*/false, is_post_crash_launch,
StartupBrowserCreator::WasRestarted());
tab_groups::MaybeShowSharedTabGroupVersionOutOfDateModal(browser);
tab_groups::MaybeShowSharedTabGroupVersionUpToDateToast(browser);
if (base::FeatureList::IsEnabled(features::kNonMilestoneUpdateToast)) {
std::string current_version_string =
current_chrome_version_string_for_testing_.has_value()
? current_chrome_version_string_for_testing_.value()
: CHROME_VERSION_STRING;
MaybeShowNonMilestoneUpdateToast(browser, current_version_string);
}
}
StartupBrowserCreatorImpl::DetermineStartupTabsResult::
DetermineStartupTabsResult(StartupTabs tabs, LaunchResult launch_result)
: tabs(std::move(tabs)), launch_result(launch_result) {}
StartupBrowserCreatorImpl::DetermineStartupTabsResult::
DetermineStartupTabsResult(DetermineStartupTabsResult&&) = default;
StartupBrowserCreatorImpl::DetermineStartupTabsResult&
StartupBrowserCreatorImpl::DetermineStartupTabsResult::operator=(
DetermineStartupTabsResult&&) = default;
StartupBrowserCreatorImpl::DetermineStartupTabsResult::
~DetermineStartupTabsResult() = default;
StartupBrowserCreatorImpl::DetermineStartupTabsResult
StartupBrowserCreatorImpl::DetermineStartupTabs(
const StartupTabProvider& provider,
chrome::startup::IsProcessStartup process_startup,
bool is_incognito_or_guest,
bool is_post_crash_launch,
bool promotions_enabled,
bool whats_new_enabled,
bool privacy_sandbox_dialog_required) {
StartupTabs tabs =
provider.GetCommandLineTabs(*command_line_, cur_dir_, profile_);
LaunchResult launch_result =
tabs.empty() ? LaunchResult::kNormally : LaunchResult::kWithGivenUrls;
if (whats_new_enabled && (launch_result == LaunchResult::kWithGivenUrls ||
is_incognito_or_guest || is_post_crash_launch)) {
whats_new::LogStartupType(whats_new::StartupType::kIneligible);
}
// Only the New Tab Page or command line URLs may be shown in incognito mode.
// A similar policy exists for crash recovery launches, to prevent getting the
// user stuck in a crash loop.
if (is_incognito_or_guest || is_post_crash_launch) {
if (!tabs.empty()) {
return {std::move(tabs), launch_result};
}
return {StartupTabs({StartupTab(GURL(chrome::kChromeUINewTabURL))}),
launch_result};
}
// A trigger on a profile may indicate that we should show a tab which
// offers to reset the user's settings. When this appears, it is first, and
// may be shown alongside command-line tabs.
StartupTabs reset_tabs = provider.GetResetTriggerTabs(profile_);
// URLs passed on the command line supersede all others, except pinned tabs.
PrependTabs(reset_tabs, &tabs);
if (launch_result == LaunchResult::kNormally) {
// An initial preferences file provided with this distribution may specify
// tabs to be displayed on first run, overriding all non-command-line tabs,
// including the profile reset tab.
StartupTabs distribution_tabs =
provider.GetDistributionFirstRunTabs(browser_creator_);
if (!distribution_tabs.empty()) {
return {std::move(distribution_tabs), launch_result};
}
// Whether a first run experience was or will be shown as part of this
// startup.
bool has_first_run_experience = false;
if (promotions_enabled) {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
if (is_first_run_ == chrome::startup::IsFirstRun::kYes) {
// We just showed the first run experience in the Desktop FRE window.
has_first_run_experience = true;
}
#endif
// Potentially add the What's New Page. Note that the What's New page
// should never be shown in the same session as any first-run onboarding
// tabs. It also shouldn't be shown with reset tabs that are required to
// always be the first foreground tab.
if (!has_first_run_experience && reset_tabs.empty()) {
StartupTabs new_features_tabs;
new_features_tabs = provider.GetNewFeaturesTabs(whats_new_enabled);
AppendTabs(new_features_tabs, &tabs);
} else if (whats_new_enabled) {
whats_new::LogStartupType(whats_new::StartupType::kOverridden);
}
}
// If the user has set the preference indicating URLs to show on opening,
// read and add those.
StartupTabs prefs_tabs =
provider.GetPreferencesTabs(*command_line_, profile_);
AppendTabs(prefs_tabs, &tabs);
// Potentially add the New Tab Page.
// Note that URLs from preferences are explicitly meant to override showing
// the NTP.
if (prefs_tabs.empty()) {
AppendTabs(provider.GetNewTabPageTabs(*command_line_, profile_), &tabs);
}
// Potentially add a tab appropriate to display the Privacy Sandbox
// confirmaton dialog on top of. Ideally such a tab will already exist
// in |tabs|, and no additional tab will be required.
if (privacy_sandbox_dialog_required &&
launch_result == LaunchResult::kNormally) {
AppendTabs(provider.GetPrivacySandboxTabs(profile_, tabs), &tabs);
}
}
// Maybe add any tabs which the user has previously pinned.
AppendTabs(provider.GetPinnedTabs(*command_line_, profile_), &tabs);
return {std::move(tabs), launch_result};
}
bool StartupBrowserCreatorImpl::MaybeAsyncRestore(
const StartupTabs& tabs,
chrome::startup::IsProcessStartup process_startup,
bool is_post_crash_launch) {
// Restore is performed synchronously on startup, and is never performed when
// launching after crashing.
if (process_startup == chrome::startup::IsProcessStartup::kYes ||
is_post_crash_launch) {
return false;
}
// Note: there's no session service in incognito or guest mode.
if (!SessionServiceFactory::GetForProfileForSessionRestore(profile_)) {
return false;
}
bool restore_apps =
ShouldRestoreApps(StartupBrowserCreator::WasRestarted(), profile_);
// Note: there's no session service in incognito or guest mode.
SessionService* service =
SessionServiceFactory::GetForProfileForSessionRestore(profile_);
return service && service->RestoreIfNecessary(tabs, restore_apps);
}
Browser* StartupBrowserCreatorImpl::RestoreOrCreateBrowser(
const StartupTabs& tabs,
BrowserOpenBehavior behavior,
SessionRestore::BehaviorBitmask restore_options,
chrome::startup::IsProcessStartup process_startup,
bool is_post_crash_launch) {
Browser* browser = nullptr;
if (behavior == BrowserOpenBehavior::SYNCHRONOUS_RESTORE) {
// It's worth noting that this codepath is not hit by crash restore
// because we want to avoid a crash restore loop, so we don't
// automatically restore after a crash.
// Crash restores are triggered via session_crashed_bubble_view.cc
if (ShouldRestoreApps(StartupBrowserCreator::WasRestarted(), profile_)) {
restore_options |= SessionRestore::RESTORE_APPS;
}
browser = SessionRestore::RestoreSession(profile_, nullptr, restore_options,
tabs);
if (browser) {
return browser;
}
} else if (behavior == BrowserOpenBehavior::USE_EXISTING ||
behavior ==
BrowserOpenBehavior::USE_EXISTING_AND_OVERWRITE_ACTIVE_TAB) {
browser = chrome::FindTabbedBrowser(
profile_, process_startup == chrome::startup::IsProcessStartup::kYes);
}
base::AutoReset<bool> synchronous_launch_resetter(
&StartupBrowserCreator::in_synchronous_profile_launch_, true);
// OpenTabsInBrowser requires at least one tab be passed. As a fallback to
// prevent a crash, use the NTP if |tabs| is empty. This could happen if
// we expected a session restore to happen but it did not occur/succeed.
browser = OpenTabsInBrowser(
browser, process_startup,
(tabs.empty()
? StartupTabs({StartupTab(GURL(chrome::kChromeUINewTabURL))})
: tabs),
(behavior == BrowserOpenBehavior::USE_EXISTING_AND_OVERWRITE_ACTIVE_TAB
? (TabOverWrite::kYes)
: (TabOverWrite::kNo)));
// Now that a restore is no longer possible, it is safe to clear session
// cookie/storage, unless this is a crash recovery.
if (!is_post_crash_launch) {
profile_->GetDefaultStoragePartition()->DeleteStaleSessionData();
}
return browser;
}
// static
StartupBrowserCreatorImpl::BrowserOpenBehavior
StartupBrowserCreatorImpl::DetermineBrowserOpenBehavior(
const SessionStartupPref& pref,
BrowserOpenBehaviorOptions options) {
if (!(options & PROCESS_STARTUP)) {
// For existing processes, restore would have happened before invoking this
// function. If Chrome was launched with passed URLs, assume these should
// be appended to an existing window if possible, unless overridden by a
// switch.
if (options & HAS_CMD_LINE_TABS && !(options & HAS_NEW_WINDOW_SWITCH)) {
// If not a new window and the kSameTab switch is included then the
// active tab will be overwritten (if one exists).
if (options & HAS_SAME_TAB_SWITCH) {
return BrowserOpenBehavior::USE_EXISTING_AND_OVERWRITE_ACTIVE_TAB;
}
return BrowserOpenBehavior::USE_EXISTING;
}
return BrowserOpenBehavior::NEW;
}
if (pref.ShouldRestoreLastSession()) {
// Don't perform a session restore on a post-crash launch, as this could
// cause a crash loop.
if (!(options & IS_POST_CRASH_LAUNCH)) {
return BrowserOpenBehavior::SYNCHRONOUS_RESTORE;
}
}
return BrowserOpenBehavior::NEW;
}
// static
SessionRestore::BehaviorBitmask
StartupBrowserCreatorImpl::DetermineSynchronousRestoreOptions(
bool has_create_browser_default,
bool has_create_browser_switch,
bool was_mac_login_or_resume,
bool restore_tabbed_browser) {
SessionRestore::BehaviorBitmask options = SessionRestore::SYNCHRONOUS;
if (restore_tabbed_browser) {
options |= SessionRestore::RESTORE_BROWSER;
}
// Suppress the creation of a new window on Mac when restoring with no windows
// if launching Chrome via a login item or the resume feature in OS 10.7+.
if (!was_mac_login_or_resume &&
(has_create_browser_default || has_create_browser_switch)) {
options |= SessionRestore::ALWAYS_CREATE_TABBED_BROWSER;
}
return options;
}
// static
void StartupBrowserCreatorImpl::MaybeShowNonMilestoneUpdateToast(
Browser* browser,
const std::string& current_version_string) {
if (!browser) {
return;
}
PrefService* local_state = g_browser_process->local_state();
std::string last_version_string =
local_state->GetString(prefs::kNonMilestoneUpdateToastVersion);
if (IsNonMilestoneUpdate(last_version_string, current_version_string)) {
browser->GetFeatures().toast_controller()->MaybeShowToast(
ToastParams(ToastId::kNonMilestoneUpdate));
}
local_state->SetString(prefs::kNonMilestoneUpdateToastVersion,
current_version_string);
}
bool StartupBrowserCreatorImpl::IsNonMilestoneUpdate(
const std::string& last_version_string,
const std::string& current_version_string) {
base::Version last_version(last_version_string);
base::Version current_version(current_version_string);
if (!last_version.IsValid() || !current_version.IsValid()) {
return false;
}
return last_version.components()[0] == current_version.components()[0] &&
last_version < current_version;
}
// static
bool StartupBrowserCreatorImpl::IsKioskModeEnabled() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kKioskMode);
}