blob: 88825221abfeac34ecc635e96ae7070ac4ee40d1 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_LOGIN_DEMO_MODE_DEMO_SETUP_CONTROLLER_H_
#define CHROME_BROWSER_ASH_LOGIN_DEMO_MODE_DEMO_SETUP_CONTROLLER_H_
#include <string>
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#include "chrome/browser/ash/login/enrollment/enrollment_launcher.h"
#include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"
namespace policy {
class EnrollmentStatus;
}
namespace ash {
class DemoComponents;
// Controls enrollment flow for setting up Demo Mode.
class DemoSetupController
: public EnrollmentLauncher::EnrollmentStatusConsumer {
public:
// All steps required for setup.
enum class DemoSetupStep {
// Downloading Demo Mode resources.
kDownloadResources,
// Enrolling in Demo Mode.
kEnrollment,
// Setup is complete.
kComplete,
};
// The types of the result of each component loading during the demo mode
// setup process. This enum is tied directly to a UMA enum
// `DemoModeSetupComponentLoadingResult` defined in
// //tools/metrics/histograms/enums.xml, and should always reflect it (do not
// change one without changing the other). Entries should never be modified or
// reordered. Entries can only be removed by deprecating it and its value
// should never be reused. New ones should be added to the end (right before
// the max value).
enum class DemoSetupComponentLoadingResult {
// The app component loading success and the resources component loading
// success.
kAppSuccessResourcesSuccess = 0,
// The app component loading success and the resources component loading
// failure.
kAppSuccessResourcesFailure = 1,
// The app component loading failure and the resources component loading
// success.
kAppFailureResourcesSuccess = 2,
// The app component loading failure and the resources component loading
// failure.
kAppFailureResourcesFailure = 3,
// Add future entries above this comment, in sync with enums.xml.
// Update kMaxValue to the last value.
kMaxValue = kAppFailureResourcesFailure,
};
// Contains information related to setup error.
class DemoSetupError {
public:
// The type of setup error. This enum is tied directly to a UMA enum
// `DemoModeSetupError` defined in //tools/metrics/histograms/enums.xml, and
// should always reflect it (do not change one without changing the other).
// Entries should never be modified or reordered. Entries can only be
// removed by deprecating it and its value should never be reused. New ones
// should be added to the end (right before the max value).
enum class ErrorCode {
// Cannot perform offline setup without online FRE check.
kOnlineFRECheckRequired = 0,
// Cannot load online component.
kOnlineComponentError = 1,
// Invalid request to DMServer.
kInvalidRequest = 2,
// Request to DMServer failed, because of network error.
kRequestNetworkError = 3,
// DMServer temporary unavailable.
kTemporaryUnavailable = 4,
// DMServer returned abnormal response code.
kResponseError = 5,
// DMServer response cannot be decoded.
kResponseDecodingError = 6,
// Device management not supported for demo account.
kDemoAccountError = 7,
// DMServer cannot find the device.
kDeviceNotFound = 8,
// Invalid device management token.
kInvalidDMToken = 9,
// Serial number invalid or unknown to DMServer,
kInvalidSerialNumber = 10,
// Device id conflict.
kDeviceIdError = 11,
// Not enough licenses or domain expired.
kLicenseError = 12,
// Device was deprovisioned.ec
kDeviceDeprovisioned = 13,
// Device belongs to different domain (FRE).
kDomainMismatch = 14,
// Management request could not be signed by the client.
kSigningError = 15,
// DMServer could not find policy for the device.
kPolicyNotFound = 16,
// ARC disabled for demo domain.
kArcError = 17,
// Cannot determine server-backed state keys.
kNoStateKeys = 18,
// Failed to fetch robot account auth or refresh token.
kRobotFetchError = 19,
// Failed to fetch robot account refresh token.
kRobotStoreError = 20,
// Unsuppored device mode returned by the server.
kBadMode = 21,
// Could not fetch registration cert,
kCertFetchError = 22,
// Could not fetch the policy.
kPolicyFetchError = 23,
// Policy validation failed.
kPolicyValidationError = 24,
// Timeout during locking the device.
kLockTimeout = 25,
// Error during locking the device.
kLockError = 26,
// Device locked to different domain on mode.
kAlreadyLocked = 27,
// Error while installing online policy.
kOnlineStoreError = 28,
// Could not determine device model or serial number.
kMachineIdentificationError = 29,
// Could not store DM token.
kDMTokenStoreError = 30,
// Unexpected/fatal error.
kUnexpectedError = 31,
// Too many requests error.
kTooManyRequestsError = 32,
// No Error - Success Code. This is only used to record the UMA metrics so
// we can know the success rate of the whole demo mode setup process.
kSuccess = 33,
// Add future entries above this comment, in sync with enums.xml.
// Update kMaxValue to the last value.
kMaxValue = kSuccess,
};
// Type of recommended recovery from the setup error.
enum class RecoveryMethod {
// Retry demo setup.
kRetry,
// Reboot and retry demo setup.
kReboot,
// Powerwash and retry demo setup.
kPowerwash,
// Check network and retry demo setup.
kCheckNetwork,
// Cannot perform offline setup - online setup might work.
kOnlineOnly,
// Unknown recovery method.
kUnknown,
};
static DemoSetupError CreateFromEnrollmentStatus(
const policy::EnrollmentStatus& status);
static DemoSetupError CreateFromOtherEnrollmentError(
EnrollmentLauncher::OtherError error);
static DemoSetupError CreateFromComponentError(
component_updater::ComponentManagerAsh::Error error,
std::string component_name);
DemoSetupError(ErrorCode error_code, RecoveryMethod recovery_method);
DemoSetupError(ErrorCode error_code,
RecoveryMethod recovery_method,
const std::string& debug_message);
~DemoSetupError();
ErrorCode error_code() const { return error_code_; }
RecoveryMethod recovery_method() const { return recovery_method_; }
std::u16string GetLocalizedErrorMessage() const;
std::u16string GetLocalizedRecoveryMessage() const;
std::string GetDebugDescription() const;
private:
ErrorCode error_code_;
RecoveryMethod recovery_method_;
std::string debug_message_;
};
// Demo mode setup callbacks.
using OnSetupSuccess = base::OnceClosure;
using OnSetupError = base::OnceCallback<void(const DemoSetupError&)>;
using OnSetCurrentSetupStep =
base::RepeatingCallback<void(const DemoSetupStep)>;
// Clears demo device enrollment requisition if it is set.
static void ClearDemoRequisition();
// Utility method that returns whether demo mode is allowed on the device.
static bool IsDemoModeAllowed();
// Utility method that returns whether demo mode setup flow is in progress in
// OOBE.
static bool IsOobeDemoSetupFlowInProgress();
// If the current country requires customization, returns an user email that
// corresponds to the sub organization the device should be enrolled into.
// If chrome flag "--demo-mode-enrolling-username" is set for test, it
// will override the current country-derived user. If neither of above is
// true, returns an empty string.
static std::string GetSubOrganizationEmail();
// Returns a dictionary mapping setup steps to step indices.
static base::Value::Dict GetDemoSetupSteps();
// Converts a step enum to a string e.g. to sent to JavaScript.
static std::string GetDemoSetupStepString(const DemoSetupStep step_enum);
DemoSetupController();
DemoSetupController(const DemoSetupController&) = delete;
DemoSetupController& operator=(const DemoSetupController&) = delete;
~DemoSetupController() override;
// Sets demo mode config that will be used to setup the device. It has to be
// set before calling Enroll().
void set_demo_config(DemoSession::DemoModeConfig demo_config) {
demo_config_ = demo_config;
}
// Set a canonicalized (whitespace and punctuation removed, case homogenized)
// version of the retailer name string.
void SetAndCanonicalizeRetailerName(const std::string& retailer_name);
std::string get_retailer_name_for_testing() { return retailer_name_; }
void set_store_number(const std::string& store_number) {
store_number_ = store_number;
}
// Initiates enrollment that sets up the device in the demo mode domain. The
// `enrollment_type_` determines whether online or offline setup will be
// performed and it should be set with set_enrollment_type() before calling
// Enroll(). `on_setup_success` will be called when enrollment finishes
// successfully. `on_setup_error` will be called when enrollment finishes with
// an error. `set_current_setup_step` will be called when an enrollment step
// completes.
void Enroll(OnSetupSuccess on_setup_success,
OnSetupError on_setup_error,
const OnSetCurrentSetupStep& set_current_setup_step);
// Converts a relative path to an absolute path under the preinstalled demo
// resources mount. Returns an empty string if the preinstalled demo resources
// are not mounted.
base::FilePath GetPreinstalledDemoResourcesPath(
const base::FilePath& relative_path);
// EnrollmentLauncher::EnrollmentStatusConsumer:
void OnDeviceEnrolled() override;
void OnEnrollmentError(policy::EnrollmentStatus status) override;
void OnAuthError(const GoogleServiceAuthError& error) override;
void OnOtherError(EnrollmentLauncher::OtherError error) override;
void OnDeviceAttributeUploadCompleted(bool success) override;
void OnDeviceAttributeUpdatePermission(bool granted) override;
void SetCrOSComponentLoadErrorForTest(
component_updater::ComponentManagerAsh::Error error);
void EnableLoadRealComponentsForTest();
private:
// Attempts to load the demo SWA and demo resources ChromeOS components for
// online enrollment and pass the results to OnDemoComponentsLoaded().
void LoadDemoComponents();
// Callback to initiate online enrollment once both the demo-mode-resources
// (sample photos, Android APKs) and demo-mode-app (demo SWA content) ChromeOS
// components have loaded.
// If the components loaded successfully, registers and sets up the device in
// the demo mode domain. If the component couldn't be loaded, demo setup
// will fail.
void OnDemoComponentsLoaded();
// Called when device is marked as registered and the second part of OOBE flow
// is completed. This is the last step of demo mode setup flow.
void OnDeviceRegistered();
// Sets current setup step.
void SetCurrentSetupStep(DemoSetupStep current_step);
// Finish the flow with an error.
void SetupFailed(const DemoSetupError& error);
// Clears the internal state.
void Reset();
// Keeps track of when downloading demo mode resources begins.
base::TimeTicks download_start_time_;
// Keeps track of when enrolling in enterprise) begins.
base::TimeTicks enroll_start_time_;
// Keeps track of how many times an operator has been required to retry
// setup.
int num_setup_retries_ = 0;
// Name of retailer entered during setup flow. Corresponds to the
// kDemoModeRetailerId pref.
std::string retailer_name_;
// Store number entered during setup flow. Corresponds to the kDemoModeStoreId
// pref.
std::string store_number_;
// Demo mode configuration type that will be setup when Enroll() is called.
// Should be set explicitly.
DemoSession::DemoModeConfig demo_config_ = DemoSession::DemoModeConfig::kNone;
// Error code to use when attempting to load the demo resources CrOS
// component.
component_updater::ComponentManagerAsh::Error component_error_for_tests_ =
component_updater::ComponentManagerAsh::Error::NONE;
// Callback to call when setup step is updated.
OnSetCurrentSetupStep set_current_setup_step_;
// Callback to call when enrollment finishes with an error.
OnSetupError on_setup_error_;
// Callback to call when enrollment finishes successfully.
OnSetupSuccess on_setup_success_;
std::unique_ptr<EnrollmentLauncher> enrollment_launcher_;
// The Demo Mode Resources ChromeOS Component downloaded for online Demo Mode.
std::unique_ptr<DemoComponents> demo_components_;
bool load_real_components_for_test_ = false;
base::WeakPtrFactory<DemoSetupController> weak_ptr_factory_{this};
};
} // namespace ash
#endif // CHROME_BROWSER_ASH_LOGIN_DEMO_MODE_DEMO_SETUP_CONTROLLER_H_