| // Copyright 2020 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/ash/login/session/user_session_initializer.h" |
| |
| #include "ash/components/pcie_peripheral/pcie_peripheral_manager.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "base/files/file_util.h" |
| #include "base/path_service.h" |
| #include "base/system/sys_info.h" |
| #include "base/task/post_task.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "chrome/browser/ash/arc/session/arc_service_launcher.h" |
| #include "chrome/browser/ash/camera_mic/vm_camera_mic_manager.h" |
| #include "chrome/browser/ash/child_accounts/child_status_reporting_service_factory.h" |
| #include "chrome/browser/ash/child_accounts/child_user_service_factory.h" |
| #include "chrome/browser/ash/child_accounts/family_user_metrics_service_factory.h" |
| #include "chrome/browser/ash/child_accounts/screen_time_controller_factory.h" |
| #include "chrome/browser/ash/crostini/crostini_manager.h" |
| #include "chrome/browser/ash/lock_screen_apps/state_controller.h" |
| #include "chrome/browser/ash/login/startup_utils.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_manager.h" |
| #include "chrome/browser/ash/plugin_vm/plugin_vm_manager_factory.h" |
| #include "chrome/browser/ash/profiles/profile_helper.h" |
| #include "chrome/browser/ash/settings/cros_settings.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browser_process_platform_part_chromeos.h" |
| #include "chrome/browser/chromeos/eche_app/eche_app_manager_factory.h" |
| #include "chrome/browser/chromeos/phonehub/phone_hub_manager_factory.h" |
| #include "chrome/browser/chromeos/policy/reporting/app_install_event_log_manager_wrapper.h" |
| #include "chrome/browser/chromeos/policy/reporting/extension_install_event_log_manager_wrapper.h" |
| #include "chrome/browser/component_updater/crl_set_component_installer.h" |
| #include "chrome/browser/component_updater/sth_set_component_remover.h" |
| #include "chrome/browser/google/google_brand_chromeos.h" |
| #include "chrome/browser/net/nss_context.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/ui/ash/clipboard_image_model_factory_impl.h" |
| #include "chrome/browser/ui/ash/holding_space/holding_space_keyed_service_factory.h" |
| #include "chrome/browser/ui/ash/media_client_impl.h" |
| #include "chrome/browser/ui/webui/settings/chromeos/peripheral_data_access_handler.h" |
| #include "chrome/common/pref_names.h" |
| #include "chromeos/dbus/pciguard/pciguard_client.h" |
| #include "chromeos/network/network_cert_loader.h" |
| #include "chromeos/tpm/install_attributes.h" |
| #include "components/prefs/pref_service.h" |
| |
| #if BUILDFLAG(ENABLE_RLZ) |
| #include "chrome/browser/rlz/chrome_rlz_tracker_delegate.h" |
| #include "components/rlz/rlz_tracker.h" |
| #endif |
| |
| namespace ash { |
| namespace { |
| |
| // TODO(https://crbug.com/1164001): remove when moved to ash:: |
| using ::chromeos::InstallAttributes; |
| |
| UserSessionInitializer* g_instance = nullptr; |
| |
| #if BUILDFLAG(ENABLE_RLZ) |
| // Flag file that disables RLZ tracking, when present. |
| const base::FilePath::CharType kRLZDisabledFlagName[] = |
| FILE_PATH_LITERAL(".rlz_disabled"); |
| |
| base::FilePath GetRlzDisabledFlagPath() { |
| base::FilePath homedir; |
| base::PathService::Get(base::DIR_HOME, &homedir); |
| return homedir.Append(kRLZDisabledFlagName); |
| } |
| |
| UserSessionInitializer::RlzInitParams CollectRlzParams() { |
| UserSessionInitializer::RlzInitParams params; |
| params.disabled = base::PathExists(GetRlzDisabledFlagPath()); |
| params.time_since_oobe_completion = |
| StartupUtils::GetTimeSinceOobeFlagFileCreation(); |
| return params; |
| } |
| #endif |
| |
| // Callback to GetNSSCertDatabaseForProfile. It passes the user-specific NSS |
| // database to NetworkCertLoader. It must be called for primary user only. |
| void OnGetNSSCertDatabaseForUser(net::NSSCertDatabase* database) { |
| if (!NetworkCertLoader::IsInitialized()) |
| return; |
| |
| NetworkCertLoader::Get()->SetUserNSSDB(database); |
| } |
| |
| void OnNoiseCancellationSupportedRetrieved( |
| absl::optional<bool> noise_cancellation_supported) { |
| DCHECK(features::IsInputNoiseCancellationUiEnabled()); |
| if (noise_cancellation_supported.has_value() && |
| noise_cancellation_supported.value()) { |
| PrefService* local_state = g_browser_process->local_state(); |
| const bool noise_cancellation_enabled = |
| local_state->GetBoolean(prefs::kInputNoiseCancellationEnabled); |
| chromeos::CrasAudioClient::Get()->SetNoiseCancellationEnabled( |
| noise_cancellation_enabled); |
| } |
| } |
| |
| } // namespace |
| |
| UserSessionInitializer::UserSessionInitializer() { |
| DCHECK(!g_instance); |
| g_instance = this; |
| } |
| |
| UserSessionInitializer::~UserSessionInitializer() { |
| DCHECK(g_instance); |
| g_instance = nullptr; |
| } |
| |
| // static |
| UserSessionInitializer* UserSessionInitializer::Get() { |
| return g_instance; |
| } |
| |
| void UserSessionInitializer::OnUserProfileLoaded(const AccountId& account_id) { |
| Profile* profile = ProfileHelper::Get()->GetProfileByAccountId(account_id); |
| user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile); |
| |
| if (user_manager::UserManager::Get()->GetPrimaryUser() == user) { |
| // TODO(https://crbug.com/1208416): Investigate why OnUserProfileLoaded |
| // is called more than once. |
| if (primary_profile_ != nullptr) { |
| NOTREACHED(); |
| CHECK_EQ(primary_profile_, profile); |
| return; |
| } |
| primary_profile_ = profile; |
| |
| InitRlz(profile); |
| InitializeCerts(profile); |
| InitializeCRLSetFetcher(); |
| InitializeCertificateTransparencyComponents(user); |
| InitializePrimaryProfileServices(profile, user); |
| |
| FamilyUserMetricsServiceFactory::GetForBrowserContext(profile); |
| } |
| |
| if (user->GetType() == user_manager::USER_TYPE_CHILD) |
| InitializeChildUserServices(profile); |
| } |
| |
| void UserSessionInitializer::InitializeChildUserServices(Profile* profile) { |
| ChildStatusReportingServiceFactory::GetForBrowserContext(profile); |
| ChildUserServiceFactory::GetForBrowserContext(profile); |
| ScreenTimeControllerFactory::GetForBrowserContext(profile); |
| } |
| |
| void UserSessionInitializer::InitRlz(Profile* profile) { |
| #if BUILDFLAG(ENABLE_RLZ) |
| // Initialize the brand code in the local prefs if it does not exist yet or |
| // if it is empty. The latter is to correct a problem in older builds where |
| // an empty brand code would be persisted if the first login after OOBE was |
| // a guest session. |
| if (!g_browser_process->local_state()->HasPrefPath(::prefs::kRLZBrand) || |
| g_browser_process->local_state() |
| ->Get(::prefs::kRLZBrand) |
| ->GetString() |
| .empty()) { |
| // Read brand code asynchronously from an OEM data and repost ourselves. |
| google_brand::chromeos::InitBrand(base::BindOnce( |
| &UserSessionInitializer::InitRlz, weak_factory_.GetWeakPtr(), profile)); |
| return; |
| } |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, |
| {base::MayBlock(), base::TaskPriority::BEST_EFFORT, |
| base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, |
| base::BindOnce(&CollectRlzParams), |
| base::BindOnce(&UserSessionInitializer::InitRlzImpl, |
| weak_factory_.GetWeakPtr(), profile)); |
| #endif |
| } |
| |
| void UserSessionInitializer::InitializeCerts(Profile* profile) { |
| // Now that the user profile has been initialized |
| // `GetNSSCertDatabaseForProfile` is safe to be used. |
| if (NetworkCertLoader::IsInitialized() && |
| base::SysInfo::IsRunningOnChromeOS()) { |
| GetNSSCertDatabaseForProfile(profile, |
| base::BindOnce(&OnGetNSSCertDatabaseForUser)); |
| } |
| } |
| |
| void UserSessionInitializer::InitializeCRLSetFetcher() { |
| component_updater::ComponentUpdateService* cus = |
| g_browser_process->component_updater(); |
| if (cus) |
| component_updater::RegisterCRLSetComponent(cus); |
| } |
| |
| void UserSessionInitializer::InitializeCertificateTransparencyComponents( |
| const user_manager::User* user) { |
| const std::string username_hash = user->username_hash(); |
| if (!username_hash.empty()) { |
| base::FilePath path = |
| ProfileHelper::GetProfilePathByUserIdHash(username_hash); |
| component_updater::DeleteLegacySTHSet(path); |
| } |
| } |
| |
| void UserSessionInitializer::InitializePrimaryProfileServices( |
| Profile* profile, |
| const user_manager::User* user) { |
| lock_screen_apps::StateController::Get()->SetPrimaryProfile(profile); |
| |
| if (user->GetType() == user_manager::USER_TYPE_REGULAR) { |
| // App install logs for extensions and ARC++ are uploaded via the user's |
| // communication channel with the management server. This channel exists for |
| // regular users only. `AppInstallEventLogManagerWrapper` and |
| // `ExtensionInstallEventLogManagerWrapper` manages their own lifetime and |
| // self-destruct on logout. |
| policy::AppInstallEventLogManagerWrapper::CreateForProfile(profile); |
| policy::ExtensionInstallEventLogManagerWrapper::CreateForProfile(profile); |
| } |
| |
| arc::ArcServiceLauncher::Get()->OnPrimaryUserProfilePrepared(profile); |
| |
| crostini::CrostiniManager* crostini_manager = |
| crostini::CrostiniManager::GetForProfile(profile); |
| if (crostini_manager) |
| crostini_manager->MaybeUpdateCrostini(); |
| |
| if (features::IsClipboardHistoryEnabled()) { |
| clipboard_image_model_factory_impl_ = |
| std::make_unique<ClipboardImageModelFactoryImpl>(profile); |
| } |
| |
| g_browser_process->platform_part()->InitializePrimaryProfileServices(profile); |
| } |
| |
| void UserSessionInitializer::OnUserSessionStarted(bool is_primary_user) { |
| Profile* profile = ProfileManager::GetActiveUserProfile(); |
| DCHECK(profile); |
| |
| // Ensure that the `HoldingSpaceKeyedService` for `profile` is created. |
| HoldingSpaceKeyedServiceFactory::GetInstance()->GetService(profile); |
| |
| if (is_primary_user) { |
| DCHECK_EQ(primary_profile_, profile); |
| |
| // Ensure that PhoneHubManager and EcheAppManager are created for the |
| // primary profile. |
| phonehub::PhoneHubManagerFactory::GetForProfile(profile); |
| eche_app::EcheAppManagerFactory::GetForProfile(profile); |
| |
| plugin_vm::PluginVmManager* plugin_vm_manager = |
| plugin_vm::PluginVmManagerFactory::GetForProfile(primary_profile_); |
| if (plugin_vm_manager) |
| plugin_vm_manager->OnPrimaryUserSessionStarted(); |
| |
| VmCameraMicManager::Get()->OnPrimaryUserSessionStarted(primary_profile_); |
| |
| // Pciguard can only be set by non-guest, primary users. By default, |
| // Pciguard is turned on. |
| if (PciePeripheralManager::IsInitialized()) { |
| PciePeripheralManager::Get()->SetPcieTunnelingAllowedState( |
| chromeos::settings::PeripheralDataAccessHandler::GetPrefState()); |
| } |
| PciguardClient::Get()->SendExternalPciDevicesPermissionState( |
| chromeos::settings::PeripheralDataAccessHandler::GetPrefState()); |
| |
| if (features::IsInputNoiseCancellationUiEnabled()) { |
| chromeos::CrasAudioClient::Get()->GetNoiseCancellationSupported( |
| base::BindOnce(&OnNoiseCancellationSupportedRetrieved)); |
| } |
| } |
| } |
| |
| void UserSessionInitializer::PreStartSession() { |
| NetworkCertLoader::Get()->MarkUserNSSDBWillBeInitialized(); |
| } |
| |
| void UserSessionInitializer::InitRlzImpl(Profile* profile, |
| const RlzInitParams& params) { |
| #if BUILDFLAG(ENABLE_RLZ) |
| // If RLZ is disabled then clear the brand for the session. |
| // |
| // RLZ is disabled if disabled explicitly OR if the device's enrollment |
| // state is not yet known. The device's enrollment state is definitively |
| // known once the device is locked. Note that for enrolled devices, the |
| // enrollment login locks the device. |
| // |
| // There the following cases to consider when a session starts: |
| // |
| // 1) This is a regular session. |
| // 1a) The device is LOCKED. Thus, the enrollment state is KNOWN. |
| // 1b) The device is NOT LOCKED. This should only happen on the first |
| // regular login (due to lock race condition with this code) if the |
| // device is NOT enrolled; thus, the enrollment state is also KNOWN. |
| // |
| // 2) This is a guest session. |
| // 2a) The device is LOCKED. Thus, the enrollment state is KNOWN. |
| // 2b) The device is NOT locked. This should happen if ONLY Guest mode |
| // sessions have ever been used on this device. This is the only |
| // situation where the enrollment state is NOT KNOWN at this point. |
| |
| PrefService* local_state = g_browser_process->local_state(); |
| if (params.disabled || (profile->IsGuestSession() && |
| !InstallAttributes::Get()->IsDeviceLocked())) { |
| // Empty brand code means an organic install (no RLZ pings are sent). |
| google_brand::chromeos::ClearBrandForCurrentSession(); |
| } |
| if (params.disabled != local_state->GetBoolean(::prefs::kRLZDisabled)) { |
| // When switching to RLZ enabled/disabled state, clear all recorded events. |
| rlz::RLZTracker::ClearRlzState(); |
| local_state->SetBoolean(::prefs::kRLZDisabled, params.disabled); |
| } |
| // Init the RLZ library. |
| int ping_delay = |
| profile->GetPrefs()->GetInteger(::prefs::kRlzPingDelaySeconds); |
| // Negative ping delay means to send ping immediately after a first search is |
| // recorded. |
| bool send_ping_immediately = ping_delay < 0; |
| base::TimeDelta delay = base::TimeDelta::FromSeconds(abs(ping_delay)) - |
| params.time_since_oobe_completion; |
| rlz::RLZTracker::SetRlzDelegate( |
| base::WrapUnique(new ChromeRLZTrackerDelegate)); |
| rlz::RLZTracker::InitRlzDelayed( |
| user_manager::UserManager::Get()->IsCurrentUserNew(), |
| send_ping_immediately, delay, |
| ChromeRLZTrackerDelegate::IsGoogleDefaultSearch(profile), |
| ChromeRLZTrackerDelegate::IsGoogleHomepage(profile), |
| ChromeRLZTrackerDelegate::IsGoogleInStartpages(profile)); |
| #endif |
| if (init_rlz_impl_closure_for_testing_) |
| std::move(init_rlz_impl_closure_for_testing_).Run(); |
| inited_for_testing_ = true; |
| } |
| |
| } // namespace ash |