| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/login/session/chrome_session_manager.h" |
| |
| #include <memory> |
| |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_process_platform_part_chromeos.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h" |
| #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" |
| #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" |
| #include "chrome/browser/chromeos/arc/arc_service_launcher.h" |
| #include "chrome/browser/chromeos/boot_times_recorder.h" |
| #include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service_factory.h" |
| #include "chrome/browser/chromeos/child_accounts/screen_time_controller_factory.h" |
| #include "chrome/browser/chromeos/crostini/crostini_manager.h" |
| #include "chrome/browser/chromeos/lock_screen_apps/state_controller.h" |
| #include "chrome/browser/chromeos/login/demo_mode/demo_resources.h" |
| #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" |
| #include "chrome/browser/chromeos/login/login_wizard.h" |
| #include "chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h" |
| #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h" |
| #include "chrome/browser/chromeos/login/session/user_session_manager.h" |
| #include "chrome/browser/chromeos/login/startup_utils.h" |
| #include "chrome/browser/chromeos/login/wizard_controller.h" |
| #include "chrome/browser/chromeos/policy/app_install_event_log_manager_wrapper.h" |
| #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" |
| #include "chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/tether/tether_service.h" |
| #include "chrome/browser/chromeos/tpm_firmware_update_notification.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/ui/app_list/app_list_client_impl.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/constants/chromeos_switches.h" |
| #include "chromeos/cryptohome/cryptohome_parameters.h" |
| #include "chromeos/dbus/session_manager/session_manager_client.h" |
| #include "components/account_id/account_id.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/user_manager/user_manager.h" |
| #include "components/user_manager/user_names.h" |
| #include "components/user_manager/user_type.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/service_manager_connection.h" |
| #include "services/identity/public/cpp/identity_manager.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| // Whether kiosk auto launch should be started. |
| bool ShouldAutoLaunchKioskApp(const base::CommandLine& command_line) { |
| KioskAppManager* app_manager = KioskAppManager::Get(); |
| return command_line.HasSwitch(switches::kLoginManager) && |
| !command_line.HasSwitch(switches::kForceLoginManagerInTests) && |
| app_manager->IsAutoLaunchEnabled() && |
| KioskAppLaunchError::Get() == KioskAppLaunchError::NONE && |
| // IsOobeCompleted() is needed to prevent kiosk session start in case |
| // of enterprise rollback, when keeping the enrollment, policy, not |
| // clearing TPM, but wiping stateful partition. |
| StartupUtils::IsOobeCompleted(); |
| } |
| |
| // Starts kiosk app auto launch and shows the splash screen. |
| void StartKioskSession() { |
| // Kiosk app launcher starts with login state. |
| session_manager::SessionManager::Get()->SetSessionState( |
| session_manager::SessionState::LOGIN_PRIMARY); |
| |
| ShowLoginWizard(chromeos::OobeScreen::SCREEN_APP_LAUNCH_SPLASH); |
| |
| // Login screen is skipped but 'login-prompt-visible' signal is still needed. |
| VLOG(1) << "Kiosk app auto launch >> login-prompt-visible"; |
| SessionManagerClient::Get()->EmitLoginPromptVisible(); |
| } |
| |
| // Starts the login/oobe screen. |
| void StartLoginOobeSession() { |
| // State will be defined once out-of-box/login branching is complete. |
| ShowLoginWizard(OobeScreen::SCREEN_UNKNOWN); |
| |
| // Reset reboot after update flag when login screen is shown. |
| policy::BrowserPolicyConnectorChromeOS* connector = |
| g_browser_process->platform_part()->browser_policy_connector_chromeos(); |
| if (!connector->IsEnterpriseManaged()) { |
| PrefService* local_state = g_browser_process->local_state(); |
| local_state->ClearPref(prefs::kRebootAfterUpdate); |
| } |
| } |
| |
| // Starts Chrome with an existing user session. Possible cases: |
| // 1. Chrome is restarted after crash. |
| // 2. Chrome is restarted for Guest session. |
| // 3. Chrome is started in browser_tests skipping the login flow. |
| // 4. Chrome is started on dev machine i.e. not on Chrome OS device w/o |
| // login flow. In that case --login-user=[user_manager::kStubUserEmail] is |
| // added. See PreEarlyInitialization(). |
| void StartUserSession(Profile* user_profile, const std::string& login_user_id) { |
| base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| |
| if (command_line->HasSwitch(chromeos::switches::kLoginUser)) { |
| // This is done in SessionManager::OnProfileCreated during normal login. |
| UserSessionManager* user_session_mgr = UserSessionManager::GetInstance(); |
| user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
| const user_manager::User* user = user_manager->GetActiveUser(); |
| if (!user) { |
| // This is possible if crash occured after profile removal |
| // (see crbug.com/178290 for some more info). |
| LOG(ERROR) << "Could not get active user after crash."; |
| return; |
| } |
| |
| chromeos::DemoSession* demo_session = chromeos::DemoSession::Get(); |
| // In demo session, delay starting user session until the offline demo |
| // session resources have been loaded. |
| if (demo_session && demo_session->started() && |
| !demo_session->resources()->loaded()) { |
| demo_session->EnsureOfflineResourcesLoaded( |
| base::BindOnce(&StartUserSession, user_profile, login_user_id)); |
| LOG(WARNING) << "Delay demo user session start until offline demo " |
| << "resources are loaded"; |
| return; |
| } |
| |
| user_session_mgr->InitRlz(user_profile); |
| user_session_mgr->InitializeCerts(user_profile); |
| user_session_mgr->InitializeCRLSetFetcher(user); |
| user_session_mgr->InitializeCertificateTransparencyComponents(user); |
| |
| ProfileHelper::Get()->ProfileStartup(user_profile); |
| |
| lock_screen_apps::StateController::Get()->SetPrimaryProfile(user_profile); |
| |
| if (user->GetType() == user_manager::USER_TYPE_REGULAR) { |
| // App install logs are uploaded via the user's communication channel with |
| // the management server. This channel exists for regular users only. |
| // The |AppInstallEventLogManagerWrapper| manages its own lifetime and |
| // self-destructs on logout. |
| policy::AppInstallEventLogManagerWrapper::CreateForProfile(user_profile); |
| } |
| arc::ArcServiceLauncher::Get()->OnPrimaryUserProfilePrepared(user_profile); |
| |
| crostini::CrostiniManager* crostini_manager = |
| crostini::CrostiniManager::GetForProfile(user_profile); |
| if (crostini_manager) |
| crostini_manager->MaybeUpgradeCrostini(); |
| |
| if (user->GetType() == user_manager::USER_TYPE_CHILD) { |
| ScreenTimeControllerFactory::GetForBrowserContext(user_profile); |
| ConsumerStatusReportingServiceFactory::GetForBrowserContext(user_profile); |
| } |
| |
| // Send the PROFILE_PREPARED notification and call SessionStarted() |
| // so that the Launcher and other Profile dependent classes are created. |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, |
| content::NotificationService::AllSources(), |
| content::Details<Profile>(user_profile)); |
| |
| // This call will set session state to SESSION_STATE_ACTIVE (same one). |
| session_manager::SessionManager::Get()->SessionStarted(); |
| |
| // Now is the good time to retrieve other logged in users for this session. |
| // First user has been already marked as logged in and active in |
| // PreProfileInit(). Restore sessions for other users in the background. |
| user_session_mgr->RestoreActiveSessions(); |
| } |
| |
| bool is_running_test = command_line->HasSwitch(::switches::kTestName) || |
| command_line->HasSwitch(::switches::kTestType); |
| if (!is_running_test) { |
| // We did not log in (we crashed or are debugging), so we need to |
| // restore Sync. |
| UserSessionManager::GetInstance()->RestoreAuthenticationSession( |
| user_profile); |
| |
| TetherService* tether_service = TetherService::Get(user_profile); |
| if (tether_service) |
| tether_service->StartTetherIfPossible(); |
| |
| // Associates AppListClient with the current active profile. |
| AppListClientImpl::GetInstance()->UpdateProfile(); |
| } |
| |
| UserSessionManager::GetInstance()->CheckEolStatus(user_profile); |
| tpm_firmware_update::ShowNotificationIfNeeded(user_profile); |
| g_browser_process->platform_part() |
| ->browser_policy_connector_chromeos() |
| ->GetTPMAutoUpdateModePolicyHandler() |
| ->ShowTPMAutoUpdateNotificationIfNeeded(); |
| |
| ArcTermsOfServiceScreen::MaybeLaunchArcSettings(user_profile); |
| SyncConsentScreen::MaybeLaunchSyncConsentSettings(user_profile); |
| UserSessionManager::GetInstance()->StartAccountManagerMigration(user_profile); |
| } |
| |
| } // namespace |
| |
| ChromeSessionManager::ChromeSessionManager() |
| : oobe_configuration_(std::make_unique<OobeConfiguration>()) {} |
| ChromeSessionManager::~ChromeSessionManager() {} |
| |
| void ChromeSessionManager::Initialize( |
| const base::CommandLine& parsed_command_line, |
| Profile* profile, |
| bool is_running_test) { |
| // Tests should be able to tune login manager before showing it. Thus only |
| // show login UI (login and out-of-box) in normal (non-testing) mode with |
| // --login-manager switch and if test passed --force-login-manager-in-tests. |
| bool force_login_screen_in_test = |
| parsed_command_line.HasSwitch(switches::kForceLoginManagerInTests); |
| |
| const std::string cryptohome_id = |
| parsed_command_line.GetSwitchValueASCII(switches::kLoginUser); |
| const AccountId login_account_id( |
| cryptohome::Identification::FromString(cryptohome_id).GetAccountId()); |
| |
| KioskAppManager::RemoveObsoleteCryptohomes(); |
| ArcKioskAppManager::RemoveObsoleteCryptohomes(); |
| |
| if (ShouldAutoLaunchKioskApp(parsed_command_line)) { |
| VLOG(1) << "Starting Chrome with kiosk auto launch."; |
| StartKioskSession(); |
| return; |
| } |
| |
| DemoSession::PreloadOfflineResourcesIfInDemoMode(); |
| if (parsed_command_line.HasSwitch(switches::kLoginManager) && |
| (!is_running_test || force_login_screen_in_test)) { |
| VLOG(1) << "Starting Chrome with login/oobe screen."; |
| oobe_configuration_->CheckConfiguration(); |
| StartLoginOobeSession(); |
| return; |
| } else if (is_running_test) { |
| oobe_configuration_->CheckConfiguration(); |
| } |
| |
| if (login_account_id == user_manager::StubAccountId()) { |
| // Start a user session with stub user. This also happens on a dev machine |
| // when running Chrome w/o login flow. See PreEarlyInitialization(). |
| // In these contexts, emulate as if sync has been initialized. |
| VLOG(1) << "Starting Chrome with stub login."; |
| |
| // TODO(https://crbug.com/814787): Determine the right long-term flow here. |
| std::string login_user_id = login_account_id.GetUserEmail(); |
| IdentityManagerFactory::GetForProfile(profile)->LegacySetPrimaryAccount( |
| login_user_id, login_user_id); |
| StartUserSession(profile, login_user_id); |
| return; |
| } |
| |
| VLOG(1) << "Starting Chrome with a user session."; |
| StartUserSession(profile, login_account_id.GetUserEmail()); |
| } |
| |
| void ChromeSessionManager::SessionStarted() { |
| session_manager::SessionManager::SessionStarted(); |
| SetSessionState(session_manager::SessionState::ACTIVE); |
| |
| // Notifies UserManager so that it can update login state. |
| user_manager::UserManager* user_manager = user_manager::UserManager::Get(); |
| if (user_manager) |
| user_manager->OnSessionStarted(); |
| |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_SESSION_STARTED, |
| content::Source<session_manager::SessionManager>(this), |
| content::Details<const user_manager::User>( |
| user_manager->GetActiveUser())); |
| } |
| |
| void ChromeSessionManager::NotifyUserLoggedIn(const AccountId& user_account_id, |
| const std::string& user_id_hash, |
| bool browser_restart, |
| bool is_child) { |
| BootTimesRecorder* btl = BootTimesRecorder::Get(); |
| btl->AddLoginTimeMarker("UserLoggedIn-Start", false); |
| session_manager::SessionManager::NotifyUserLoggedIn( |
| user_account_id, user_id_hash, browser_restart, is_child); |
| btl->AddLoginTimeMarker("UserLoggedIn-End", false); |
| } |
| |
| } // namespace chromeos |