blob: a01a87e97dfc0a97bcc7e0f2b483638b234813f5 [file] [log] [blame]
// Copyright (c) 2012 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/wizard_controller.h"
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string>
#include <utility>
#include <vector>
#include "ash/public/cpp/ash_switches.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/json/json_string_value_serializer.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/chromeos/customization/customization_document.h"
#include "chrome/browser/chromeos/login/configuration_keys.h"
#include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
#include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h"
#include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h"
#include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/hwid_checker.h"
#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
#include "chrome/browser/chromeos/login/screens/app_downloading_screen.h"
#include "chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h"
#include "chrome/browser/chromeos/login/screens/assistant_optin_flow_screen.h"
#include "chrome/browser/chromeos/login/screens/demo_preferences_screen.h"
#include "chrome/browser/chromeos/login/screens/demo_setup_screen.h"
#include "chrome/browser/chromeos/login/screens/device_disabled_screen.h"
#include "chrome/browser/chromeos/login/screens/discover_screen.h"
#include "chrome/browser/chromeos/login/screens/enable_debugging_screen.h"
#include "chrome/browser/chromeos/login/screens/encryption_migration_screen.h"
#include "chrome/browser/chromeos/login/screens/error_screen.h"
#include "chrome/browser/chromeos/login/screens/eula_screen.h"
#include "chrome/browser/chromeos/login/screens/fingerprint_setup_screen.h"
#include "chrome/browser/chromeos/login/screens/hid_detection_screen.h"
#include "chrome/browser/chromeos/login/screens/kiosk_autolaunch_screen.h"
#include "chrome/browser/chromeos/login/screens/kiosk_enable_screen.h"
#include "chrome/browser/chromeos/login/screens/marketing_opt_in_screen.h"
#include "chrome/browser/chromeos/login/screens/multidevice_setup_screen.h"
#include "chrome/browser/chromeos/login/screens/network_error.h"
#include "chrome/browser/chromeos/login/screens/network_screen.h"
#include "chrome/browser/chromeos/login/screens/recommend_apps_screen.h"
#include "chrome/browser/chromeos/login/screens/reset_screen.h"
#include "chrome/browser/chromeos/login/screens/supervision_transition_screen.h"
#include "chrome/browser/chromeos/login/screens/sync_consent_screen.h"
#include "chrome/browser/chromeos/login/screens/update_required_screen.h"
#include "chrome/browser/chromeos/login/screens/update_screen.h"
#include "chrome/browser/chromeos/login/screens/welcome_screen.h"
#include "chrome/browser/chromeos/login/screens/wrong_hwid_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/ui/login_display_host.h"
#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
#include "chrome/browser/chromeos/net/delay_network_call.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/stats_reporting_controller.h"
#include "chrome/browser/chromeos/system/device_disabling_manager.h"
#include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
#include "chrome/browser/chromeos/system/timezone_util.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/metrics/metrics_reporting_state.h"
#include "chrome/browser/policy/profile_policy_connector_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/login_screen_client.h"
#include "chrome/browser/ui/ash/tablet_mode_client.h"
#include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
#include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "chromeos/constants/chromeos_constants.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager/session_manager_client.h"
#include "chromeos/geolocation/simple_geolocation_provider.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_handler_callbacks.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/portal_detector/network_portal_detector.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/cros_settings_provider.h"
#include "chromeos/settings/timezone_settings.h"
#include "chromeos/timezone/timezone_provider.h"
#include "components/arc/arc_prefs.h"
#include "components/arc/arc_util.h"
#include "components/arc/session/arc_bridge_service.h"
#include "components/crash/content/app/breakpad_linux.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_types.h"
#include "content/public/common/service_manager_connection.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/service_manager/public/cpp/connector.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "ui/base/accelerators/accelerator.h"
using content::BrowserThread;
namespace {
// Interval in ms which is used for smooth screen showing.
static int g_show_delay_ms = 400;
// Total timezone resolving process timeout.
const unsigned int kResolveTimeZoneTimeoutSeconds = 60;
// Stores the list of all screens that should be shown when resuming OOBE.
const chromeos::OobeScreen kResumableScreens[] = {
chromeos::OobeScreen::SCREEN_OOBE_WELCOME,
chromeos::OobeScreen::SCREEN_OOBE_NETWORK,
chromeos::OobeScreen::SCREEN_OOBE_UPDATE,
chromeos::OobeScreen::SCREEN_OOBE_EULA,
chromeos::OobeScreen::SCREEN_OOBE_ENROLLMENT,
chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE,
chromeos::OobeScreen::SCREEN_SYNC_CONSENT,
chromeos::OobeScreen::SCREEN_FINGERPRINT_SETUP,
chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
chromeos::OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK,
chromeos::OobeScreen::SCREEN_RECOMMEND_APPS,
chromeos::OobeScreen::SCREEN_APP_DOWNLOADING,
chromeos::OobeScreen::SCREEN_DISCOVER,
chromeos::OobeScreen::SCREEN_MARKETING_OPT_IN,
chromeos::OobeScreen::SCREEN_MULTIDEVICE_SETUP,
};
// Checks if device is in tablet mode, and that HID-detection screen is not
// disabled by flag.
bool CanShowHIDDetectionScreen() {
return !TabletModeClient::Get()->tablet_mode_enabled() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDisableHIDDetectionOnOOBE) &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
ash::switches::kAshEnableTabletMode);
}
bool IsResumableScreen(chromeos::OobeScreen screen) {
for (const auto& resumable_screen : kResumableScreens) {
if (screen == resumable_screen)
return true;
}
return false;
}
struct Entry {
chromeos::OobeScreen screen;
const char* uma_name;
};
// Some screens had multiple different names in the past (they have since been
// unified). We need to always use the same name for UMA stats, though.
constexpr const Entry kLegacyUmaOobeScreenNames[] = {
{chromeos::OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE, "arc_tos"},
{chromeos::OobeScreen::SCREEN_OOBE_ENROLLMENT, "enroll"},
{chromeos::OobeScreen::SCREEN_OOBE_WELCOME, "network"},
{chromeos::OobeScreen::SCREEN_CREATE_SUPERVISED_USER_FLOW_DEPRECATED,
"supervised-user-creation-flow"},
{chromeos::OobeScreen::SCREEN_TERMS_OF_SERVICE, "tos"}};
void RecordUMAHistogramForOOBEStepCompletionTime(chromeos::OobeScreen screen,
base::TimeDelta step_time) {
// Fetch screen name; make sure to use initial UMA name if the name has
// changed.
std::string screen_name = chromeos::GetOobeScreenName(screen);
for (const auto& entry : kLegacyUmaOobeScreenNames) {
if (entry.screen == screen) {
screen_name = entry.uma_name;
break;
}
}
screen_name[0] = std::toupper(screen_name[0]);
std::string histogram_name = "OOBE.StepCompletionTime." + screen_name;
// Equivalent to using UMA_HISTOGRAM_MEDIUM_TIMES. UMA_HISTOGRAM_MEDIUM_TIMES
// can not be used here, because |histogram_name| is calculated dynamically
// and changes from call to call.
base::HistogramBase* histogram = base::Histogram::FactoryTimeGet(
histogram_name, base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromMinutes(3), 50,
base::HistogramBase::kUmaTargetedHistogramFlag);
histogram->AddTime(step_time);
}
bool IsRemoraRequisition() {
policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->GetDeviceCloudPolicyManager();
return policy_manager && policy_manager->IsRemoraRequisition();
}
// Return false if the logged in user is a managed or child account. Otherwise,
// return true if the feature flag for recommend app screen is on.
bool ShouldShowRecommendAppsScreen() {
const user_manager::UserManager* user_manager =
user_manager::UserManager::Get();
DCHECK(user_manager->IsUserLoggedIn());
bool is_managed_account =
policy::ProfilePolicyConnectorFactory::IsProfileManaged(
ProfileManager::GetActiveUserProfile());
bool is_child_account = user_manager->IsLoggedInAsChildUser();
return !is_managed_account && !is_child_account &&
base::FeatureList::IsEnabled(features::kOobeRecommendAppsScreen);
}
chromeos::LoginDisplayHost* GetLoginDisplayHost() {
return chromeos::LoginDisplayHost::default_host();
}
chromeos::OobeUI* GetOobeUI() {
auto* host = chromeos::LoginDisplayHost::default_host();
return host ? host->GetOobeUI() : nullptr;
}
scoped_refptr<network::SharedURLLoaderFactory>&
GetSharedURLLoaderFactoryForTesting() {
static base::NoDestructor<scoped_refptr<network::SharedURLLoaderFactory>>
loader;
return *loader;
}
} // namespace
namespace chromeos {
// static
const int WizardController::kMinAudibleOutputVolumePercent = 10;
// static
bool WizardController::skip_post_login_screens_ = false;
// static
bool WizardController::skip_enrollment_prompts_ = false;
// static
#if defined(GOOGLE_CHROME_BUILD)
bool WizardController::is_official_build_ = true;
#else
bool WizardController::is_official_build_ = false;
#endif
// static
WizardController* WizardController::default_controller() {
auto* host = chromeos::LoginDisplayHost::default_host();
return host ? host->GetWizardController() : nullptr;
}
///////////////////////////////////////////////////////////////////////////////
// WizardController, public:
PrefService* WizardController::local_state_for_testing_ = nullptr;
WizardController::WizardController()
: screen_manager_(std::make_unique<ScreenManager>()),
network_state_helper_(std::make_unique<login::NetworkStateHelper>()) {
// In session OOBE was initiated from voice interaction keyboard shortcuts.
is_in_session_oobe_ =
session_manager::SessionManager::Get()->IsSessionStarted();
AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
if (accessibility_manager) {
// accessibility_manager could be null in Tests.
accessibility_subscription_ = accessibility_manager->RegisterCallback(
base::Bind(&WizardController::OnAccessibilityStatusChanged,
weak_factory_.GetWeakPtr()));
}
}
WizardController::~WizardController() {
screen_manager_.reset();
}
void WizardController::Init(OobeScreen first_screen) {
screen_manager_->Init(CreateScreens());
VLOG(1) << "Starting OOBE wizard with screen: "
<< GetOobeScreenName(first_screen);
first_screen_ = first_screen;
bool oobe_complete = StartupUtils::IsOobeCompleted();
if (!oobe_complete)
UpdateOobeConfiguration();
if (!oobe_complete || first_screen == OobeScreen::SCREEN_SPECIAL_OOBE)
is_out_of_box_ = true;
// This is a hacky way to check for local state corruption, because
// it depends on the fact that the local state is loaded
// synchronously and at the first demand. IsEnterpriseManaged()
// check is required because currently powerwash is disabled for
// enterprise-enrolled devices.
//
// TODO (ygorshenin@): implement handling of the local state
// corruption in the case of asynchronious loading.
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
if (!connector->IsEnterpriseManaged()) {
const PrefService::PrefInitializationStatus status =
GetLocalState()->GetInitializationStatus();
if (status == PrefService::INITIALIZATION_STATUS_ERROR) {
OnLocalStateInitialized(false);
return;
}
if (status == PrefService::INITIALIZATION_STATUS_WAITING) {
GetLocalState()->AddPrefInitObserver(
base::BindOnce(&WizardController::OnLocalStateInitialized,
weak_factory_.GetWeakPtr()));
}
}
if (CrosSettings::IsInitialized()) {
guest_mode_policy_subscription_ = CrosSettings::Get()->AddSettingsObserver(
kAccountsPrefAllowGuest,
base::BindRepeating(&WizardController::OnGuestModePolicyUpdated,
weak_factory_.GetWeakPtr()));
}
// Use the saved screen preference from Local State.
const std::string screen_pref =
GetLocalState()->GetString(prefs::kOobeScreenPending);
if (is_out_of_box_ && !screen_pref.empty() &&
(first_screen == OobeScreen::SCREEN_UNKNOWN ||
first_screen == OobeScreen::SCREEN_TEST_NO_WINDOW)) {
first_screen_ = GetOobeScreenFromName(screen_pref);
}
AdvanceToScreen(first_screen_);
if (!IsMachineHWIDCorrect() && !StartupUtils::IsDeviceRegistered() &&
first_screen_ == OobeScreen::SCREEN_UNKNOWN)
ShowWrongHWIDScreen();
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kOobeSkipToLogin)) {
SkipToLoginForTesting(LoginScreenContext());
}
}
ErrorScreen* WizardController::GetErrorScreen() {
return GetOobeUI()->GetErrorScreen();
}
BaseScreen* WizardController::GetScreen(OobeScreen screen) {
if (screen == OobeScreen::SCREEN_ERROR_MESSAGE)
return GetErrorScreen();
return screen_manager_->GetScreen(screen);
}
void WizardController::SetCurrentScreenForTesting(BaseScreen* screen) {
current_screen_ = screen;
}
void WizardController::SetSharedURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory> factory) {
auto& testing_factory = GetSharedURLLoaderFactoryForTesting();
testing_factory = std::move(factory);
}
std::vector<std::unique_ptr<BaseScreen>> WizardController::CreateScreens() {
OobeUI* oobe_ui = GetOobeUI();
std::vector<std::unique_ptr<BaseScreen>> result;
auto append = [&](std::unique_ptr<BaseScreen> screen) {
result.emplace_back(std::move(screen));
};
if (oobe_ui->display_type() == OobeUI::kOobeDisplay) {
append(std::make_unique<WelcomeScreen>(
oobe_ui->GetWelcomeView(),
base::BindRepeating(&WizardController::OnWelcomeScreenExit,
weak_factory_.GetWeakPtr())));
}
append(std::make_unique<NetworkScreen>(
oobe_ui->GetNetworkScreenView(),
base::BindRepeating(&WizardController::OnNetworkScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<UpdateScreen>(
this, oobe_ui->GetUpdateView(), oobe_ui->GetErrorScreen(),
base::BindRepeating(&WizardController::OnUpdateScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<EulaScreen>(
oobe_ui->GetEulaView(),
base::BindRepeating(&WizardController::OnEulaScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<EnrollmentScreen>(
oobe_ui->GetEnrollmentScreenView(),
base::BindRepeating(&WizardController::OnEnrollmentScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<chromeos::ResetScreen>(
oobe_ui->GetResetView(), oobe_ui->GetErrorScreen(),
base::BindRepeating(&WizardController::OnResetScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<chromeos::DemoSetupScreen>(
oobe_ui->GetDemoSetupScreenView(),
base::BindRepeating(&WizardController::OnDemoSetupScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<chromeos::DemoPreferencesScreen>(
oobe_ui->GetDemoPreferencesScreenView(),
base::BindRepeating(&WizardController::OnDemoPreferencesScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<EnableDebuggingScreen>(
oobe_ui->GetEnableDebuggingScreenView(),
base::BindRepeating(&WizardController::OnEnableDebuggingScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<KioskEnableScreen>(
oobe_ui->GetKioskEnableScreenView(),
base::BindRepeating(&WizardController::OnKioskEnableScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<KioskAutolaunchScreen>(
oobe_ui->GetKioskAutolaunchScreenView(),
base::BindRepeating(&WizardController::OnKioskAutolaunchScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<TermsOfServiceScreen>(
oobe_ui->GetTermsOfServiceScreenView(),
base::BindRepeating(&WizardController::OnTermsOfServiceScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<SyncConsentScreen>(
oobe_ui->GetSyncConsentScreenView(),
base::BindRepeating(&WizardController::OnSyncConsentScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<ArcTermsOfServiceScreen>(
oobe_ui->GetArcTermsOfServiceScreenView(),
base::BindRepeating(&WizardController::OnArcTermsOfServiceScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<RecommendAppsScreen>(
oobe_ui->GetRecommendAppsScreenView(),
base::BindRepeating(&WizardController::OnRecommendAppsScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<AppDownloadingScreen>(
oobe_ui->GetAppDownloadingScreenView(),
base::BindRepeating(&WizardController::OnAppDownloadingScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<WrongHWIDScreen>(
oobe_ui->GetWrongHWIDScreenView(),
base::BindRepeating(&WizardController::OnWrongHWIDScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<chromeos::HIDDetectionScreen>(
oobe_ui->GetHIDDetectionView(),
base::BindRepeating(&WizardController::OnHidDetectionScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<AutoEnrollmentCheckScreen>(
oobe_ui->GetAutoEnrollmentCheckScreenView(), oobe_ui->GetErrorScreen(),
base::BindRepeating(&WizardController::OnAutoEnrollmentCheckScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<DeviceDisabledScreen>(
oobe_ui->GetDeviceDisabledScreenView()));
append(std::make_unique<EncryptionMigrationScreen>(
oobe_ui->GetEncryptionMigrationScreenView()));
append(std::make_unique<SupervisionTransitionScreen>(
oobe_ui->GetSupervisionTransitionScreenView(),
base::BindRepeating(&WizardController::OnSupervisionTransitionScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<UpdateRequiredScreen>(
oobe_ui->GetUpdateRequiredScreenView()));
append(std::make_unique<AssistantOptInFlowScreen>(
oobe_ui->GetAssistantOptInFlowScreenView(),
base::BindRepeating(&WizardController::OnAssistantOptInFlowScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<MultiDeviceSetupScreen>(
oobe_ui->GetMultiDeviceSetupScreenView(),
base::BindRepeating(&WizardController::OnMultiDeviceSetupScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<DiscoverScreen>(
oobe_ui->GetDiscoverScreenView(),
base::BindRepeating(&WizardController::OnDiscoverScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<FingerprintSetupScreen>(
oobe_ui->GetFingerprintSetupScreenView(),
base::BindRepeating(&WizardController::OnFingerprintSetupScreenExit,
weak_factory_.GetWeakPtr())));
append(std::make_unique<MarketingOptInScreen>(
oobe_ui->GetMarketingOptInScreenView(),
base::BindRepeating(&WizardController::OnMarketingOptInScreenExit,
weak_factory_.GetWeakPtr())));
return result;
}
void WizardController::ShowWelcomeScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_WELCOME));
}
void WizardController::ShowNetworkScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_NETWORK));
}
void WizardController::ShowLoginScreen(const LoginScreenContext& context) {
// This may be triggered by multiply asynchronous events from the JS side.
if (login_screen_started_)
return;
if (!time_eula_accepted_.is_null()) {
base::TimeDelta delta = base::Time::Now() - time_eula_accepted_;
UMA_HISTOGRAM_MEDIUM_TIMES("OOBE.EULAToSignInTime", delta);
}
VLOG(1) << "Showing login screen.";
UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_SPECIAL_LOGIN);
GetLoginDisplayHost()->StartSignInScreen(context);
smooth_show_timer_.Stop();
login_screen_started_ = true;
}
void WizardController::ShowEulaScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_EULA));
}
void WizardController::ShowEnrollmentScreen() {
// Update the enrollment configuration and start the screen.
prescribed_enrollment_config_ = g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->GetPrescribedEnrollmentConfig();
StartEnrollmentScreen(false);
}
void WizardController::ShowDemoModePreferencesScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
}
void WizardController::ShowDemoModeSetupScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_DEMO_SETUP));
}
void WizardController::ShowResetScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_RESET));
}
void WizardController::ShowKioskEnableScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_KIOSK_ENABLE));
}
void WizardController::ShowKioskAutolaunchScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH));
}
void WizardController::ShowEnableDebuggingScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING));
}
void WizardController::ShowTermsOfServiceScreen() {
// Only show the Terms of Service when logging into a public account and Terms
// of Service have been specified through policy. In all other cases, advance
// to the post-ToS part immediately.
if (!user_manager::UserManager::Get()->IsLoggedInAsPublicAccount() ||
!ProfileManager::GetActiveUserProfile()->GetPrefs()->IsManagedPreference(
prefs::kTermsOfServiceURL)) {
OnTermsOfServiceAccepted();
return;
}
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_TERMS_OF_SERVICE));
}
void WizardController::ShowSyncConsentScreen() {
if (is_official_build_)
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_SYNC_CONSENT));
else
OnSyncConsentFinished();
}
void WizardController::ShowFingerprintSetupScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_FINGERPRINT_SETUP));
}
void WizardController::ShowMarketingOptInScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_MARKETING_OPT_IN));
}
void WizardController::ShowArcTermsOfServiceScreen() {
if (arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
ProfileManager::GetActiveUserProfile()->GetPrefs()->SetBoolean(
arc::prefs::kArcTermsShownInOobe, true);
} else {
ShowAssistantOptInFlowScreen();
}
}
void WizardController::ShowRecommendAppsScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_RECOMMEND_APPS));
}
void WizardController::ShowAppDownloadingScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_APP_DOWNLOADING));
}
void WizardController::ShowWrongHWIDScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_WRONG_HWID));
}
void WizardController::ShowAutoEnrollmentCheckScreen() {
AutoEnrollmentCheckScreen* screen =
AutoEnrollmentCheckScreen::Get(screen_manager());
if (retry_auto_enrollment_check_)
screen->ClearState();
screen->set_auto_enrollment_controller(GetAutoEnrollmentController());
SetCurrentScreen(screen);
}
void WizardController::ShowArcKioskSplashScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ARC_KIOSK_SPLASH));
}
void WizardController::ShowHIDDetectionScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION));
}
void WizardController::ShowDeviceDisabledScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_DEVICE_DISABLED));
}
void WizardController::ShowEncryptionMigrationScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ENCRYPTION_MIGRATION));
}
void WizardController::ShowSupervisionTransitionScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_SUPERVISION_TRANSITION));
}
void WizardController::ShowUpdateRequiredScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_UPDATE_REQUIRED));
}
void WizardController::ShowAssistantOptInFlowScreen() {
UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW));
}
void WizardController::ShowMultiDeviceSetupScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_MULTIDEVICE_SETUP));
}
void WizardController::ShowDiscoverScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_DISCOVER));
}
void WizardController::SkipToLoginForTesting(
const LoginScreenContext& context) {
VLOG(1) << "SkipToLoginForTesting.";
StartupUtils::MarkEulaAccepted();
PerformPostEulaActions();
OnDeviceDisabledChecked(false /* device_disabled */);
}
void WizardController::SkipToUpdateForTesting() {
VLOG(1) << "SkipToUpdateForTesting.";
StartupUtils::MarkEulaAccepted();
PerformPostEulaActions();
InitiateOOBEUpdate();
}
void WizardController::SkipUpdateEnrollAfterEula() {
skip_update_enroll_after_eula_ = true;
}
void WizardController::OnScreenExit(OobeScreen screen, int exit_code) {
DCHECK(current_screen_->screen_id() == screen);
VLOG(1) << "Wizard screen " << GetOobeScreenName(screen)
<< " exited with code: " << exit_code;
if (IsOOBEStepToTrack(screen)) {
RecordUMAHistogramForOOBEStepCompletionTime(
screen, base::Time::Now() - screen_show_times_[screen]);
}
}
///////////////////////////////////////////////////////////////////////////////
// WizardController, ExitHandlers:
void WizardController::OnWrongHWIDScreenExit() {
OnScreenExit(OobeScreen::SCREEN_WRONG_HWID, 0 /* exit_code */);
if (previous_screen_) {
SetCurrentScreen(previous_screen_);
} else {
ShowLoginScreen(LoginScreenContext());
}
}
void WizardController::OnHidDetectionScreenExit() {
OnScreenExit(OobeScreen::SCREEN_OOBE_HID_DETECTION, 0 /* exit_code */);
// Check for tests configuration.
if (!StartupUtils::IsOobeCompleted())
ShowWelcomeScreen();
}
void WizardController::OnWelcomeScreenExit() {
OnScreenExit(OobeScreen::SCREEN_OOBE_WELCOME, 0 /* exit_code */);
ShowNetworkScreen();
}
void WizardController::OnNetworkScreenExit(NetworkScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_OOBE_NETWORK, static_cast<int>(result));
if (result == NetworkScreen::Result::BACK) {
if (demo_setup_controller_) {
ShowDemoModePreferencesScreen();
} else {
ShowWelcomeScreen();
}
return;
}
// Update the demo setup config for demo setup flow.
if (demo_setup_controller_) {
switch (result) {
case NetworkScreen::Result::CONNECTED:
demo_setup_controller_->set_demo_config(
DemoSession::DemoModeConfig::kOnline);
break;
case NetworkScreen::Result::OFFLINE_DEMO_SETUP:
demo_setup_controller_->set_demo_config(
DemoSession::DemoModeConfig::kOffline);
break;
case NetworkScreen::Result::BACK:
NOTREACHED();
}
}
if (ShowEulaOrArcTosAfterNetworkScreen())
return;
switch (result) {
case NetworkScreen::Result::CONNECTED:
InitiateOOBEUpdate();
break;
case NetworkScreen::Result::OFFLINE_DEMO_SETUP:
// TODO(agawronska): Maybe check if device is connected to the network
// and attempt system update. It is possible to initiate offline demo
// setup on the device that is connected, although it is probably not
// common.
ShowDemoModeSetupScreen();
break;
case NetworkScreen::Result::BACK:
NOTREACHED();
}
}
bool WizardController::ShowEulaOrArcTosAfterNetworkScreen() {
if (!is_official_build_)
return false;
if (!StartupUtils::IsEulaAccepted()) {
ShowEulaScreen();
return true;
}
if (arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
ShowArcTermsOfServiceScreen();
return true;
}
// This is reachable in case of a reboot during previous OOBE flow after EULA
// was accepted and ARC terms of service handled - for example due to a forced
// update (which is the next step, with the exception of offline demo mode
// setup).
return false;
}
void WizardController::OnEulaScreenExit(EulaScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_OOBE_EULA, static_cast<int>(result));
switch (result) {
case EulaScreen::Result::ACCEPTED_WITH_USAGE_STATS_REPORTING:
OnEulaAccepted(true /*usage_statistics_reporting_enabled*/);
break;
case EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING:
OnEulaAccepted(false /*usage_statistics_reporting_enabled*/);
break;
case EulaScreen::Result::BACK:
ShowNetworkScreen();
break;
}
}
void WizardController::OnEulaAccepted(bool usage_statistics_reporting_enabled) {
time_eula_accepted_ = base::Time::Now();
StartupUtils::MarkEulaAccepted();
ChangeMetricsReportingStateWithReply(
usage_statistics_reporting_enabled,
base::BindRepeating(&WizardController::OnChangedMetricsReportingState,
weak_factory_.GetWeakPtr()));
PerformPostEulaActions();
if (arc::IsArcTermsOfServiceOobeNegotiationNeeded()) {
ShowArcTermsOfServiceScreen();
return;
} else if (demo_setup_controller_) {
ShowDemoModeSetupScreen();
}
if (skip_update_enroll_after_eula_) {
ShowAutoEnrollmentCheckScreen();
} else {
InitiateOOBEUpdate();
}
}
void WizardController::OnUpdateScreenExit(UpdateScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_OOBE_UPDATE, static_cast<int>(result));
switch (result) {
case UpdateScreen::Result::UPDATE_NOT_REQUIRED:
OnUpdateCompleted();
break;
case UpdateScreen::Result::UPDATE_ERROR:
// Ignore update errors if the OOBE flow has already completed - this
// prevents the user getting blocked from getting to the login screen.
if (is_out_of_box_) {
ShowNetworkScreen();
} else {
OnUpdateCompleted();
}
break;
}
}
void WizardController::OnUpdateCompleted() {
ShowAutoEnrollmentCheckScreen();
}
void WizardController::OnAutoEnrollmentCheckScreenExit() {
OnScreenExit(OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK, 0 /* exit_code */);
// Check whether the device is disabled. OnDeviceDisabledChecked() will be
// invoked when the result of this check is known. Until then, the current
// screen will remain visible and will continue showing a spinner.
g_browser_process->platform_part()
->device_disabling_manager()
->CheckWhetherDeviceDisabledDuringOOBE(
base::BindRepeating(&WizardController::OnDeviceDisabledChecked,
weak_factory_.GetWeakPtr()));
}
void WizardController::OnEnrollmentScreenExit(EnrollmentScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_OOBE_ENROLLMENT, static_cast<int>(result));
switch (result) {
case EnrollmentScreen::Result::COMPLETED:
OnEnrollmentDone();
break;
case EnrollmentScreen::Result::BACK:
retry_auto_enrollment_check_ = true;
ShowAutoEnrollmentCheckScreen();
break;
}
}
void WizardController::OnEnrollmentDone() {
PerformOOBECompletedActions();
// Restart to make the login page pick up the policy changes resulting from
// enrollment recovery. (Not pretty, but this codepath is rarely exercised.)
if (prescribed_enrollment_config_.mode ==
policy::EnrollmentConfig::MODE_RECOVERY ||
prescribed_enrollment_config_.mode ==
policy::EnrollmentConfig::MODE_ENROLLED_ROLLBACK) {
chrome::AttemptRestart();
return;
}
if (KioskAppManager::Get()->IsAutoLaunchEnabled())
AutoLaunchKioskApp();
else
ShowLoginScreen(LoginScreenContext());
}
void WizardController::OnEnableDebuggingScreenExit() {
OnScreenExit(OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING, 0 /* exit_code */);
OnDeviceModificationCanceled();
}
void WizardController::OnKioskEnableScreenExit() {
OnScreenExit(OobeScreen::SCREEN_KIOSK_ENABLE, 0 /* exit_code */);
ShowLoginScreen(LoginScreenContext());
}
void WizardController::OnKioskAutolaunchScreenExit(
KioskAutolaunchScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_KIOSK_AUTOLAUNCH, 0 /* exit_code */);
switch (result) {
case KioskAutolaunchScreen::Result::COMPLETED:
DCHECK(KioskAppManager::Get()->IsAutoLaunchEnabled());
AutoLaunchKioskApp();
break;
case KioskAutolaunchScreen::Result::CANCELED:
ShowLoginScreen(LoginScreenContext());
break;
}
}
void WizardController::OnDemoPreferencesScreenExit(
DemoPreferencesScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES,
static_cast<int>(result));
DCHECK(demo_setup_controller_);
switch (result) {
case DemoPreferencesScreen::Result::COMPLETED:
ShowNetworkScreen();
break;
case DemoPreferencesScreen::Result::CANCELED:
demo_setup_controller_.reset();
ShowWelcomeScreen();
break;
}
}
void WizardController::OnDemoSetupScreenExit(DemoSetupScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_OOBE_DEMO_SETUP, static_cast<int>(result));
DCHECK(demo_setup_controller_);
demo_setup_controller_.reset();
switch (result) {
case DemoSetupScreen::Result::COMPLETED:
PerformOOBECompletedActions();
ShowLoginScreen(LoginScreenContext());
break;
case DemoSetupScreen::Result::CANCELED:
ShowWelcomeScreen();
break;
}
}
void WizardController::OnTermsOfServiceScreenExit(
TermsOfServiceScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_TERMS_OF_SERVICE, static_cast<int>(result));
switch (result) {
case TermsOfServiceScreen::Result::ACCEPTED:
OnTermsOfServiceAccepted();
break;
case TermsOfServiceScreen::Result::DECLINED:
// End the session and return to the login screen.
SessionManagerClient::Get()->StopSession();
break;
}
}
void WizardController::OnTermsOfServiceAccepted() {
ShowSyncConsentScreen();
}
void WizardController::OnSyncConsentScreenExit() {
OnScreenExit(OobeScreen::SCREEN_SYNC_CONSENT, 0 /* exit_code */);
OnSyncConsentFinished();
}
void WizardController::OnSyncConsentFinished() {
ShowFingerprintSetupScreen();
}
void WizardController::OnFingerprintSetupScreenExit() {
OnScreenExit(OobeScreen::SCREEN_FINGERPRINT_SETUP, 0 /* exit_code */);
ShowDiscoverScreen();
}
void WizardController::OnDiscoverScreenExit() {
OnScreenExit(OobeScreen::SCREEN_DISCOVER, 0 /* exit_code */);
ShowMarketingOptInScreen();
}
void WizardController::OnMarketingOptInScreenExit() {
OnScreenExit(OobeScreen::SCREEN_MARKETING_OPT_IN, 0 /* exit_code */);
ShowArcTermsOfServiceScreen();
}
void WizardController::OnArcTermsOfServiceScreenExit(
ArcTermsOfServiceScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
static_cast<int>(result));
switch (result) {
case ArcTermsOfServiceScreen::Result::ACCEPTED:
OnArcTermsOfServiceAccepted();
break;
case ArcTermsOfServiceScreen::Result::SKIPPED:
OnArcTermsOfServiceSkipped();
break;
case ArcTermsOfServiceScreen::Result::BACK:
DCHECK(demo_setup_controller_);
DCHECK(StartupUtils::IsEulaAccepted());
ShowNetworkScreen();
break;
}
}
void WizardController::OnArcTermsOfServiceSkipped() {
DCHECK(!arc::IsArcTermsOfServiceOobeNegotiationNeeded());
if (is_in_session_oobe_) {
OnOobeFlowFinished();
return;
}
// If the user finished with the PlayStore Terms of Service, advance to the
// assistant opt-in flow screen.
ShowAssistantOptInFlowScreen();
}
void WizardController::OnArcTermsOfServiceAccepted() {
if (demo_setup_controller_) {
if (demo_setup_controller_->IsOfflineEnrollment()) {
ShowDemoModeSetupScreen();
} else {
InitiateOOBEUpdate();
}
return;
}
// If the recommend app screen should be shown, show it after the user
// finished with the PlayStore Terms of Service. Otherwise, advance to the
// assistant opt-in flow screen.
if (ShouldShowRecommendAppsScreen()) {
ShowRecommendAppsScreen();
} else {
ShowAssistantOptInFlowScreen();
}
}
void WizardController::OnRecommendAppsScreenExit(
RecommendAppsScreen::Result result) {
OnScreenExit(OobeScreen::SCREEN_RECOMMEND_APPS, static_cast<int>(result));
switch (result) {
case RecommendAppsScreen::Result::SELECTED:
ShowAppDownloadingScreen();
break;
case RecommendAppsScreen::Result::SKIPPED:
ShowAssistantOptInFlowScreen();
break;
}
}
void WizardController::OnAppDownloadingScreenExit() {
OnScreenExit(OobeScreen::SCREEN_APP_DOWNLOADING, 0 /* exit_code */);
ShowAssistantOptInFlowScreen();
}
void WizardController::OnAssistantOptInFlowScreenExit() {
OnScreenExit(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW, 0 /* exit_code */);
ShowMultiDeviceSetupScreen();
}
void WizardController::OnMultiDeviceSetupScreenExit() {
OnScreenExit(OobeScreen::SCREEN_MULTIDEVICE_SETUP, 0 /* exit_code */);
OnOobeFlowFinished();
}
void WizardController::OnResetScreenExit() {
OnScreenExit(OobeScreen::SCREEN_OOBE_RESET, 0 /* exit_code */);
OnDeviceModificationCanceled();
}
void WizardController::OnChangedMetricsReportingState(bool enabled) {
StatsReportingController::Get()->SetEnabled(
ProfileManager::GetActiveUserProfile(), enabled);
if (!enabled)
return;
#if defined(GOOGLE_CHROME_BUILD)
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&breakpad::InitCrashReporter, std::string()));
#endif
}
void WizardController::OnDeviceModificationCanceled() {
if (previous_screen_) {
SetCurrentScreen(previous_screen_);
} else {
ShowLoginScreen(LoginScreenContext());
}
}
void WizardController::OnSupervisionTransitionScreenExit() {
OnScreenExit(OobeScreen::SCREEN_SUPERVISION_TRANSITION, 0 /* exit_code */);
OnOobeFlowFinished();
}
void WizardController::OnOobeFlowFinished() {
if (is_in_session_oobe_ && current_screen_->screen_id() !=
OobeScreen::SCREEN_SUPERVISION_TRANSITION) {
GetLoginDisplayHost()->SetStatusAreaVisible(true);
GetLoginDisplayHost()->Finalize(base::OnceClosure());
return;
}
if (!time_oobe_started_.is_null()) {
base::TimeDelta delta = base::Time::Now() - time_oobe_started_;
UMA_HISTOGRAM_CUSTOM_TIMES("OOBE.BootToSignInCompleted", delta,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromMinutes(30), 100);
time_oobe_started_ = base::Time();
}
// Launch browser and delete login host controller.
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&UserSessionManager::DoBrowserLaunch,
base::Unretained(UserSessionManager::GetInstance()),
ProfileManager::GetActiveUserProfile(),
GetLoginDisplayHost()));
}
void WizardController::OnDeviceDisabledChecked(bool device_disabled) {
prescribed_enrollment_config_ = g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->GetPrescribedEnrollmentConfig();
bool configuration_forced_enrollment = false;
auto* start_enrollment_value = oobe_configuration_.FindKeyOfType(
configuration::kWizardAutoEnroll, base::Value::Type::BOOLEAN);
if (start_enrollment_value)
configuration_forced_enrollment = start_enrollment_value->GetBool();
if (device_disabled) {
demo_setup_controller_.reset();
ShowDeviceDisabledScreen();
} else if (demo_setup_controller_) {
ShowDemoModeSetupScreen();
} else if (skip_update_enroll_after_eula_ ||
prescribed_enrollment_config_.should_enroll() ||
configuration_forced_enrollment) {
VLOG(1) << "StartEnrollment from OnDeviceDisabledChecked(device_disabled="
<< device_disabled << ") "
<< "skip_update_enroll_after_eula_="
<< skip_update_enroll_after_eula_
<< ", prescribed_enrollment_config_.should_enroll()="
<< prescribed_enrollment_config_.should_enroll()
<< ", configuration_forced_enrollment="
<< configuration_forced_enrollment;
StartEnrollmentScreen(skip_update_enroll_after_eula_);
} else {
PerformOOBECompletedActions();
ShowLoginScreen(LoginScreenContext());
}
}
void WizardController::InitiateOOBEUpdate() {
if (IsRemoraRequisition()) {
VLOG(1) << "Skip OOBE Update for remora.";
OnUpdateCompleted();
return;
}
// If this is a Cellular First device, instruct UpdateEngine to allow
// updates over cellular data connections.
if (chromeos::switches::IsCellularFirstDevice()) {
DBusThreadManager::Get()
->GetUpdateEngineClient()
->SetUpdateOverCellularPermission(
true, base::Bind(&WizardController::StartOOBEUpdate,
weak_factory_.GetWeakPtr()));
} else {
StartOOBEUpdate();
}
}
void WizardController::StartOOBEUpdate() {
SetCurrentScreenSmooth(GetScreen(OobeScreen::SCREEN_OOBE_UPDATE), true);
UpdateScreen::Get(screen_manager())->StartNetworkCheck();
}
void WizardController::StartTimezoneResolve() {
if (!g_browser_process->platform_part()
->GetTimezoneResolverManager()
->TimeZoneResolverShouldBeRunning()) {
return;
}
auto& testing_factory = GetSharedURLLoaderFactoryForTesting();
geolocation_provider_ = std::make_unique<SimpleGeolocationProvider>(
testing_factory ? testing_factory
: g_browser_process->shared_url_loader_factory(),
SimpleGeolocationProvider::DefaultGeolocationProviderURL());
geolocation_provider_->RequestGeolocation(
base::TimeDelta::FromSeconds(kResolveTimeZoneTimeoutSeconds),
false /* send_wifi_geolocation_data */,
false /* send_cellular_geolocation_data */,
base::Bind(&WizardController::OnLocationResolved,
weak_factory_.GetWeakPtr()));
}
void WizardController::PerformPostEulaActions() {
DelayNetworkCall(
base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS),
base::Bind(&WizardController::StartTimezoneResolve,
weak_factory_.GetWeakPtr()));
DelayNetworkCall(
base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS),
ServicesCustomizationDocument::GetInstance()
->EnsureCustomizationAppliedClosure());
// Now that EULA has been accepted (for official builds), enable portal check.
// ChromiumOS builds would go though this code path too.
NetworkHandler::Get()->network_state_handler()->SetCheckPortalList(
NetworkStateHandler::kDefaultCheckPortalList);
GetAutoEnrollmentController()->Start();
GetLoginDisplayHost()->PrewarmAuthentication();
network_portal_detector::GetInstance()->Enable(true);
}
void WizardController::PerformOOBECompletedActions() {
// Avoid marking OOBE as completed multiple times if going from login screen
// to enrollment screen (and back).
if (oobe_marked_completed_) {
return;
}
UMA_HISTOGRAM_COUNTS_100(
"HIDDetection.TimesDialogShownPerOOBECompleted",
GetLocalState()->GetInteger(prefs::kTimesHIDDialogShown));
GetLocalState()->ClearPref(prefs::kTimesHIDDialogShown);
StartupUtils::MarkOobeCompleted();
oobe_marked_completed_ = true;
}
void WizardController::SetCurrentScreen(BaseScreen* new_current) {
SetCurrentScreenSmooth(new_current, false);
}
void WizardController::ShowCurrentScreen() {
// ShowCurrentScreen may get called by smooth_show_timer_ even after
// flow has been switched to sign in screen (ExistingUserController).
if (!GetOobeUI())
return;
// First remember how far have we reached so that we can resume if needed.
if (is_out_of_box_ && !demo_setup_controller_ &&
IsResumableScreen(current_screen_->screen_id())) {
StartupUtils::SaveOobePendingScreen(
GetOobeScreenName(current_screen_->screen_id()));
}
smooth_show_timer_.Stop();
UpdateStatusAreaVisibilityForScreen(current_screen_->screen_id());
current_screen_->SetConfiguration(&oobe_configuration_);
current_screen_->Show();
}
void WizardController::SetCurrentScreenSmooth(BaseScreen* new_current,
bool use_smoothing) {
VLOG(1) << "SetCurrentScreenSmooth: "
<< GetOobeScreenName(new_current->screen_id());
if (current_screen_ == new_current || new_current == nullptr ||
GetOobeUI() == nullptr) {
return;
}
smooth_show_timer_.Stop();
if (current_screen_) {
current_screen_->Hide();
current_screen_->SetConfiguration(nullptr);
}
const OobeScreen screen = new_current->screen_id();
if (IsOOBEStepToTrack(screen))
screen_show_times_[screen] = base::Time::Now();
previous_screen_ = current_screen_;
current_screen_ = new_current;
if (use_smoothing) {
smooth_show_timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(g_show_delay_ms),
this, &WizardController::ShowCurrentScreen);
} else {
ShowCurrentScreen();
}
}
void WizardController::UpdateStatusAreaVisibilityForScreen(OobeScreen screen) {
if (screen == OobeScreen::SCREEN_OOBE_WELCOME) {
// Hide the status area initially; it only appears after OOBE first animates
// in. Keep it visible if the user goes back to the existing welcome screen.
GetLoginDisplayHost()->SetStatusAreaVisible(
screen_manager_->HasScreen(OobeScreen::SCREEN_OOBE_WELCOME));
} else if (screen == OobeScreen::SCREEN_OOBE_RESET ||
screen == OobeScreen::SCREEN_KIOSK_ENABLE ||
screen == OobeScreen::SCREEN_KIOSK_AUTOLAUNCH ||
screen == OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING ||
screen == OobeScreen::SCREEN_WRONG_HWID ||
screen == OobeScreen::SCREEN_SUPERVISION_TRANSITION ||
screen == OobeScreen::SCREEN_ARC_KIOSK_SPLASH) {
GetLoginDisplayHost()->SetStatusAreaVisible(false);
} else {
GetLoginDisplayHost()->SetStatusAreaVisible(true);
}
}
void WizardController::OnHIDScreenNecessityCheck(bool screen_needed) {
if (!GetOobeUI())
return;
const auto* skip_screen_key = oobe_configuration_.FindKeyOfType(
configuration::kSkipHIDDetection, base::Value::Type::BOOLEAN);
const bool skip_screen = skip_screen_key && skip_screen_key->GetBool();
if (screen_needed && !skip_screen)
ShowHIDDetectionScreen();
else
ShowWelcomeScreen();
}
void WizardController::UpdateOobeConfiguration() {
oobe_configuration_ = base::Value(base::Value::Type::DICTIONARY);
chromeos::configuration::FilterConfiguration(
OobeConfiguration::Get()->GetConfiguration(),
chromeos::configuration::ConfigurationHandlerSide::HANDLER_CPP,
oobe_configuration_);
auto* requisition_value = oobe_configuration_.FindKeyOfType(
configuration::kDeviceRequisition, base::Value::Type::STRING);
if (requisition_value) {
auto* policy_manager = g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->GetDeviceCloudPolicyManager();
if (policy_manager) {
VLOG(1) << "Using Device Requisition from configuration"
<< requisition_value->GetString();
policy_manager->SetDeviceRequisition(requisition_value->GetString());
}
}
}
void WizardController::AdvanceToScreen(OobeScreen screen) {
if (screen == OobeScreen::SCREEN_OOBE_WELCOME) {
ShowWelcomeScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_NETWORK) {
ShowNetworkScreen();
} else if (screen == OobeScreen::SCREEN_SPECIAL_LOGIN) {
ShowLoginScreen(LoginScreenContext());
} else if (screen == OobeScreen::SCREEN_OOBE_UPDATE) {
InitiateOOBEUpdate();
} else if (screen == OobeScreen::SCREEN_OOBE_EULA) {
ShowEulaScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_RESET) {
ShowResetScreen();
} else if (screen == OobeScreen::SCREEN_KIOSK_ENABLE) {
ShowKioskEnableScreen();
} else if (screen == OobeScreen::SCREEN_KIOSK_AUTOLAUNCH) {
ShowKioskAutolaunchScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_ENABLE_DEBUGGING) {
ShowEnableDebuggingScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_ENROLLMENT) {
ShowEnrollmentScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_DEMO_SETUP) {
ShowDemoModeSetupScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES) {
ShowDemoModePreferencesScreen();
} else if (screen == OobeScreen::SCREEN_TERMS_OF_SERVICE) {
ShowTermsOfServiceScreen();
} else if (screen == OobeScreen::SCREEN_SYNC_CONSENT) {
ShowSyncConsentScreen();
} else if (screen == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE) {
ShowArcTermsOfServiceScreen();
} else if (screen == OobeScreen::SCREEN_RECOMMEND_APPS) {
ShowRecommendAppsScreen();
} else if (screen == OobeScreen::SCREEN_APP_DOWNLOADING) {
ShowAppDownloadingScreen();
} else if (screen == OobeScreen::SCREEN_WRONG_HWID) {
ShowWrongHWIDScreen();
} else if (screen == OobeScreen::SCREEN_AUTO_ENROLLMENT_CHECK) {
ShowAutoEnrollmentCheckScreen();
} else if (screen == OobeScreen::SCREEN_APP_LAUNCH_SPLASH) {
AutoLaunchKioskApp();
} else if (screen == OobeScreen::SCREEN_ARC_KIOSK_SPLASH) {
ShowArcKioskSplashScreen();
} else if (screen == OobeScreen::SCREEN_OOBE_HID_DETECTION) {
ShowHIDDetectionScreen();
} else if (screen == OobeScreen::SCREEN_DEVICE_DISABLED) {
ShowDeviceDisabledScreen();
} else if (screen == OobeScreen::SCREEN_ENCRYPTION_MIGRATION) {
ShowEncryptionMigrationScreen();
} else if (screen == OobeScreen::SCREEN_UPDATE_REQUIRED) {
ShowUpdateRequiredScreen();
} else if (screen == OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW) {
ShowAssistantOptInFlowScreen();
} else if (screen == OobeScreen::SCREEN_MULTIDEVICE_SETUP) {
ShowMultiDeviceSetupScreen();
} else if (screen == OobeScreen::SCREEN_DISCOVER) {
ShowDiscoverScreen();
} else if (screen == OobeScreen::SCREEN_FINGERPRINT_SETUP) {
ShowFingerprintSetupScreen();
} else if (screen == OobeScreen::SCREEN_MARKETING_OPT_IN) {
ShowMarketingOptInScreen();
} else if (screen == OobeScreen::SCREEN_SUPERVISION_TRANSITION) {
ShowSupervisionTransitionScreen();
} else if (screen != OobeScreen::SCREEN_TEST_NO_WINDOW) {
if (is_out_of_box_) {
time_oobe_started_ = base::Time::Now();
if (CanShowHIDDetectionScreen()) {
hid_screen_ = GetScreen(OobeScreen::SCREEN_OOBE_HID_DETECTION);
base::Callback<void(bool)> on_check =
base::Bind(&WizardController::OnHIDScreenNecessityCheck,
weak_factory_.GetWeakPtr());
GetOobeUI()->GetHIDDetectionView()->CheckIsScreenRequired(on_check);
} else {
ShowWelcomeScreen();
}
} else {
ShowLoginScreen(LoginScreenContext());
}
}
}
void WizardController::StartDemoModeSetup() {
demo_setup_controller_ = std::make_unique<DemoSetupController>();
ShowDemoModePreferencesScreen();
}
void WizardController::SimulateDemoModeSetupForTesting(
base::Optional<DemoSession::DemoModeConfig> demo_config) {
if (!demo_setup_controller_)
demo_setup_controller_ = std::make_unique<DemoSetupController>();
if (demo_config.has_value())
demo_setup_controller_->set_demo_config(*demo_config);
}
///////////////////////////////////////////////////////////////////////////////
// WizardController, BaseScreenDelegate overrides:
void WizardController::ShowErrorScreen() {
SetCurrentScreen(GetScreen(OobeScreen::SCREEN_ERROR_MESSAGE));
}
void WizardController::OnAccessibilityStatusChanged(
const AccessibilityStatusEventDetails& details) {
enum AccessibilityNotificationType type = details.notification_type;
if (type == ACCESSIBILITY_MANAGER_SHUTDOWN) {
accessibility_subscription_.reset();
return;
} else if (type != ACCESSIBILITY_TOGGLE_SPOKEN_FEEDBACK || !details.enabled) {
return;
}
CrasAudioHandler* cras = CrasAudioHandler::Get();
if (cras->IsOutputMuted()) {
cras->SetOutputMute(false);
cras->SetOutputVolumePercent(kMinAudibleOutputVolumePercent);
} else if (cras->GetOutputVolumePercent() < kMinAudibleOutputVolumePercent) {
cras->SetOutputVolumePercent(kMinAudibleOutputVolumePercent);
}
}
void WizardController::OnGuestModePolicyUpdated() {
LoginScreenClient::Get()->login_screen()->SetShowGuestButtonInOobe(
user_manager::UserManager::Get()->IsGuestSessionAllowed());
}
void WizardController::AutoLaunchKioskApp() {
KioskAppManager::App app_data;
std::string app_id = KioskAppManager::Get()->GetAutoLaunchApp();
CHECK(KioskAppManager::Get()->GetApp(app_id, &app_data));
// Wait for the |CrosSettings| to become either trusted or permanently
// untrusted.
const CrosSettingsProvider::TrustedStatus status =
CrosSettings::Get()->PrepareTrustedValues(base::Bind(
&WizardController::AutoLaunchKioskApp, weak_factory_.GetWeakPtr()));
if (status == CrosSettingsProvider::TEMPORARILY_UNTRUSTED)
return;
if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
// If the |cros_settings_| are permanently untrusted, show an error message
// and refuse to auto-launch the kiosk app.
GetErrorScreen()->SetUIState(NetworkError::UI_STATE_LOCAL_STATE_ERROR);
GetLoginDisplayHost()->SetStatusAreaVisible(false);
ShowErrorScreen();
return;
}
if (system::DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation()) {
// If the device is disabled, bail out. A device disabled screen will be
// shown by the DeviceDisablingManager.
return;
}
const bool diagnostic_mode = false;
const bool auto_launch = true;
GetLoginDisplayHost()->StartAppLaunch(app_id, diagnostic_mode, auto_launch);
}
// static
void WizardController::SetZeroDelays() {
g_show_delay_ms = 0;
}
// static
bool WizardController::IsZeroDelayEnabled() {
return g_show_delay_ms == 0;
}
// static
bool WizardController::IsOOBEStepToTrack(OobeScreen screen_id) {
return (screen_id == OobeScreen::SCREEN_OOBE_HID_DETECTION ||
screen_id == OobeScreen::SCREEN_OOBE_WELCOME ||
screen_id == OobeScreen::SCREEN_OOBE_UPDATE ||
screen_id == OobeScreen::SCREEN_OOBE_EULA ||
screen_id == OobeScreen::SCREEN_SPECIAL_LOGIN ||
screen_id == OobeScreen::SCREEN_WRONG_HWID);
}
// static
void WizardController::SkipPostLoginScreensForTesting() {
skip_post_login_screens_ = true;
if (!default_controller() || !default_controller()->current_screen())
return;
const OobeScreen current_screen_id =
default_controller()->current_screen()->screen_id();
if (current_screen_id == OobeScreen::SCREEN_TERMS_OF_SERVICE ||
current_screen_id == OobeScreen::SCREEN_SYNC_CONSENT ||
current_screen_id == OobeScreen::SCREEN_FINGERPRINT_SETUP ||
current_screen_id == OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE ||
current_screen_id == OobeScreen::SCREEN_DISCOVER ||
current_screen_id == OobeScreen::SCREEN_MARKETING_OPT_IN) {
default_controller()->OnOobeFlowFinished();
} else {
LOG(WARNING) << "SkipPostLoginScreensForTesting(): Ignore screen "
<< static_cast<int>(current_screen_id);
}
}
// static
void WizardController::SkipEnrollmentPromptsForTesting() {
skip_enrollment_prompts_ = true;
}
// static
std::unique_ptr<base::AutoReset<bool>>
WizardController::ForceOfficialBuildForTesting() {
return std::make_unique<base::AutoReset<bool>>(&is_official_build_, true);
}
// static
bool WizardController::UsingHandsOffEnrollment() {
return policy::DeviceCloudPolicyManagerChromeOS::
GetZeroTouchEnrollmentMode() ==
policy::ZeroTouchEnrollmentMode::HANDS_OFF;
}
void WizardController::OnLocalStateInitialized(bool /* succeeded */) {
if (GetLocalState()->GetInitializationStatus() !=
PrefService::INITIALIZATION_STATUS_ERROR) {
return;
}
GetErrorScreen()->SetUIState(NetworkError::UI_STATE_LOCAL_STATE_ERROR);
GetLoginDisplayHost()->SetStatusAreaVisible(false);
ShowErrorScreen();
}
PrefService* WizardController::GetLocalState() {
if (local_state_for_testing_)
return local_state_for_testing_;
return g_browser_process->local_state();
}
void WizardController::OnTimezoneResolved(
std::unique_ptr<TimeZoneResponseData> timezone,
bool server_error) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(timezone);
timezone_resolved_ = true;
base::ScopedClosureRunner inform_test(on_timezone_resolved_for_testing_);
on_timezone_resolved_for_testing_.Reset();
VLOG(1) << "Resolved local timezone={" << timezone->ToStringForDebug()
<< "}.";
if (timezone->status != TimeZoneResponseData::OK) {
LOG(WARNING) << "Resolve TimeZone: failed to resolve timezone.";
return;
}
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
if (connector->IsEnterpriseManaged()) {
std::string policy_timezone;
if (CrosSettings::Get()->GetString(kSystemTimezonePolicy,
&policy_timezone) &&
!policy_timezone.empty()) {
VLOG(1) << "Resolve TimeZone: TimeZone settings are overridden"
<< " by DevicePolicy.";
return;
}
}
if (!timezone->timeZoneId.empty()) {
VLOG(1) << "Resolve TimeZone: setting timezone to '" << timezone->timeZoneId
<< "'";
chromeos::system::SetSystemAndSigninScreenTimezone(timezone->timeZoneId);
}
}
TimeZoneProvider* WizardController::GetTimezoneProvider() {
if (!timezone_provider_) {
auto& testing_factory = GetSharedURLLoaderFactoryForTesting();
timezone_provider_ = std::make_unique<TimeZoneProvider>(
testing_factory ? testing_factory
: g_browser_process->shared_url_loader_factory(),
DefaultTimezoneProviderURL());
}
return timezone_provider_.get();
}
void WizardController::OnLocationResolved(const Geoposition& position,
bool server_error,
const base::TimeDelta elapsed) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const base::TimeDelta timeout =
base::TimeDelta::FromSeconds(kResolveTimeZoneTimeoutSeconds);
// Ignore invalid position.
if (!position.Valid())
return;
if (elapsed >= timeout) {
LOG(WARNING) << "Resolve TimeZone: got location after timeout ("
<< elapsed.InSecondsF() << " seconds elapsed). Ignored.";
return;
}
if (!g_browser_process->platform_part()
->GetTimezoneResolverManager()
->TimeZoneResolverShouldBeRunning()) {
return;
}
// WizardController owns TimezoneProvider, so timezone request is silently
// cancelled on destruction.
GetTimezoneProvider()->RequestTimezone(
position, timeout - elapsed,
base::Bind(&WizardController::OnTimezoneResolved,
weak_factory_.GetWeakPtr()));
}
bool WizardController::SetOnTimeZoneResolvedForTesting(
const base::Closure& callback) {
if (timezone_resolved_)
return false;
on_timezone_resolved_for_testing_ = callback;
return true;
}
void WizardController::StartEnrollmentScreen(bool force_interactive) {
VLOG(1) << "Showing enrollment screen."
<< " Forcing interactive enrollment: " << force_interactive << ".";
// Determine the effective enrollment configuration. If there is a valid
// prescribed configuration, use that. If not, figure out which variant of
// manual enrollment is taking place.
// If OOBE Configuration exits, it might also affect enrollment configuration.
policy::EnrollmentConfig effective_config = prescribed_enrollment_config_;
if (!effective_config.should_enroll() ||
(force_interactive && !effective_config.should_enroll_interactively())) {
effective_config.mode =
prescribed_enrollment_config_.management_domain.empty()
? policy::EnrollmentConfig::MODE_MANUAL
: policy::EnrollmentConfig::MODE_MANUAL_REENROLLMENT;
}
// If chrome version is rolled back via policy, the device is actually
// enrolled but some enrollment-flow steps still need to be taken.
auto* restore_after_rollback_value = oobe_configuration_.FindKeyOfType(
configuration::kRestoreAfterRollback, base::Value::Type::BOOLEAN);
if (restore_after_rollback_value && restore_after_rollback_value->GetBool())
effective_config.mode = policy::EnrollmentConfig::MODE_ENROLLED_ROLLBACK;
// If enrollment token is specified via OOBE configuration use corresponding
// configuration.
auto* enrollment_token = oobe_configuration_.FindKeyOfType(
configuration::kEnrollmentToken, base::Value::Type::STRING);
if (enrollment_token && !enrollment_token->GetString().empty()) {
effective_config.mode =
policy::EnrollmentConfig::MODE_ATTESTATION_ENROLLMENT_TOKEN;
effective_config.auth_mechanism =
policy::EnrollmentConfig::AUTH_MECHANISM_ATTESTATION;
effective_config.enrollment_token = enrollment_token->GetString();
}
EnrollmentScreen* screen = EnrollmentScreen::Get(screen_manager());
screen->SetEnrollmentConfig(effective_config);
UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_ENROLLMENT);
SetCurrentScreen(screen);
}
AutoEnrollmentController* WizardController::GetAutoEnrollmentController() {
if (!auto_enrollment_controller_)
auto_enrollment_controller_ = std::make_unique<AutoEnrollmentController>();
return auto_enrollment_controller_.get();
}
} // namespace chromeos