| // Copyright 2014 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_EASY_UNLOCK_EASY_UNLOCK_SERVICE_H_ |
| #define CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_H_ |
| |
| #include <memory> |
| #include <set> |
| #include <string> |
| |
| #include "base/functional/callback_forward.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/ash/login/easy_unlock/chrome_proximity_auth_client.h" |
| #include "chrome/browser/ash/login/easy_unlock/easy_unlock_auth_attempt.h" |
| #include "chrome/browser/ash/login/easy_unlock/easy_unlock_metrics.h" |
| #include "chromeos/ash/components/multidevice/remote_device_ref.h" |
| #include "chromeos/ash/components/proximity_auth/screenlock_bridge.h" |
| #include "chromeos/ash/components/proximity_auth/smart_lock_metrics_recorder.h" |
| #include "chromeos/ash/services/device_sync/public/cpp/device_sync_client.h" |
| #include "chromeos/ash/services/multidevice_setup/public/cpp/multidevice_setup_client.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| |
| class AccountId; |
| class Profile; |
| |
| namespace user_manager { |
| class User; |
| } // namespace user_manager |
| |
| namespace user_prefs { |
| class PrefRegistrySyncable; |
| } // namespace user_prefs |
| |
| namespace proximity_auth { |
| class ProximityAuthPrefManager; |
| class ProximityAuthProfilePrefManager; |
| class ProximityAuthSystem; |
| } // namespace proximity_auth |
| |
| namespace ash { |
| |
| class EasyUnlockNotificationController; |
| class SmartLockFeatureUsageMetrics; |
| enum class SmartLockState; |
| |
| namespace secure_channel { |
| class SecureChannelClient; |
| } // namespace secure_channel |
| |
| class EasyUnlockService |
| : public KeyedService, |
| public proximity_auth::ScreenlockBridge::Observer, |
| public device_sync::DeviceSyncClient::Observer, |
| public multidevice_setup::MultiDeviceSetupClient::Observer { |
| public: |
| // Gets EasyUnlockService instance. |
| static EasyUnlockService* Get(Profile* profile); |
| |
| // Gets EasyUnlockService instance associated with a user if the user is |
| // logged in and their profile is initialized. |
| static EasyUnlockService* GetForUser(const user_manager::User& user); |
| |
| // Registers Easy Unlock profile preferences. |
| static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); |
| |
| EasyUnlockService( |
| Profile* profile, |
| secure_channel::SecureChannelClient* secure_channel_client, |
| device_sync::DeviceSyncClient* device_sync_client, |
| multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client); |
| |
| // Constructor for tests. |
| EasyUnlockService( |
| Profile* profile, |
| secure_channel::SecureChannelClient* secure_channel_client, |
| std::unique_ptr<EasyUnlockNotificationController> notification_controller, |
| device_sync::DeviceSyncClient* device_sync_client, |
| multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client); |
| |
| EasyUnlockService(const EasyUnlockService&) = delete; |
| EasyUnlockService& operator=(const EasyUnlockService&) = delete; |
| ~EasyUnlockService() override; |
| |
| // Starts an auth attempt for the user associated with the service. Returns |
| // true if no other attempt is in progress and the attempt request can be |
| // processed. |
| bool AttemptAuth(const AccountId& account_id); |
| |
| // Finalizes the previously started auth attempt for easy unlock. |
| void FinalizeUnlock(bool success); |
| |
| // Returns the user currently associated with the service. |
| AccountId GetAccountId() const; |
| |
| // To be called when EasyUnlockService is "warming up", for example, on screen |
| // lock, after suspend, when the login screen is starting up, etc. During a |
| // period like this, not all sub-systems are fully initialized, particularly |
| // UnlockManager and the Bluetooth stack, so to avoid UI jank, callers can use |
| // this method to fill in the UI with an approximation of what the UI will |
| // look like in <1 second. The resulting initial state will be one of two |
| // possibilities: |
| // * SmartLockState::kConnectingToPhone: if the feature is allowed, enabled, |
| // and has kicked off a scan/connection. |
| // * SmartLockState::kDisabled: if any values above can't be confirmed. |
| SmartLockState GetInitialSmartLockState() const; |
| |
| // The last value emitted to the SmartLock.GetRemoteStatus.Unlock(.Failure) |
| // metrics. Helps to understand whether/why not Smart Lock was an available |
| // choice for unlock. Returns the empty string if the ProximityAuthSystem or |
| // the UnlockManager is uninitialized. |
| std::string GetLastRemoteStatusUnlockForLogging(); |
| |
| // Returns the ProximityAuthPrefManager, responsible for managing all |
| // EasyUnlock preferences. |
| proximity_auth::ProximityAuthPrefManager* GetProximityAuthPrefManager(); |
| |
| // Retrieves the remote device list stored for the account in |
| // |proximity_auth_system_|. |
| const multidevice::RemoteDeviceRefList GetRemoteDevicesForTesting() const; |
| |
| // Handles Easy Unlock auth failure for the user. |
| void HandleAuthFailure(const AccountId& account_id); |
| |
| // Sets the service up and schedules service initialization. |
| void Initialize(); |
| |
| // Whether easy unlock is allowed to be used. If the controlling preference |
| // is set (from policy), this returns the preference value. Otherwise, it is |
| // permitted if the flag is enabled. Virtual to allow override for testing. |
| virtual bool IsAllowed() const; |
| |
| // Whether Easy Unlock is currently enabled for this user. Virtual to allow |
| // override for testing. |
| virtual bool IsEnabled() const; |
| |
| ChromeProximityAuthClient* proximity_auth_client() { |
| return &proximity_auth_client_; |
| } |
| |
| // Updates the user pod on the lock screen for the user associated with |
| // the service to reflect the provided Smart Lock state. |
| void UpdateSmartLockState(SmartLockState state); |
| |
| private: |
| friend class EasyUnlockServiceTest; |
| |
| // KeyedService: |
| void Shutdown() override; |
| |
| // proximity_auth::ScreenlockBridge::Observer: |
| void OnScreenDidLock(proximity_auth::ScreenlockBridge::LockHandler::ScreenType |
| screen_type) override; |
| void OnScreenDidUnlock( |
| proximity_auth::ScreenlockBridge::LockHandler::ScreenType screen_type) |
| override; |
| void OnFocusedUserChanged(const AccountId& account_id) override; |
| |
| // device_sync::DeviceSyncClient::Observer: |
| void OnReady() override; |
| void OnEnrollmentFinished() override; |
| void OnNewDevicesSynced() override; |
| |
| // multidevice_setup::MultiDeviceSetupClient::Observer: |
| void OnFeatureStatesChanged( |
| const multidevice_setup::MultiDeviceSetupClient::FeatureStatesMap& |
| feature_states_map) override; |
| |
| // Returns the authentication event for a recent password unlock, |
| // according to the current state of the service. |
| EasyUnlockAuthEvent GetPasswordAuthEvent() const; |
| |
| // Returns the authentication event for a recent password unlock, |
| // according to the current state of the service. |
| SmartLockMetricsRecorder::SmartLockAuthEventPasswordState |
| GetSmartUnlockPasswordAuthEvent() const; |
| |
| multidevice::RemoteDeviceRefList GetUnlockKeys(); |
| |
| // Determines whether failure to unlock with phone should be handled as an |
| // authentication failure. |
| bool IsSmartLockStateValidOnRemoteAuthFailure() const; |
| |
| // Loads the RemoteDevice instances that will be supplied to |
| // ProximityAuthSystem. |
| void LoadRemoteDevices(); |
| |
| void NotifySmartLockAuthResult(bool success); |
| |
| // Called when the system resumes from a suspended state. |
| void OnSuspendDone(); |
| |
| // Called when the user enters password before easy unlock succeeds or fails |
| // definitively. |
| void OnUserEnteredPassword(); |
| |
| // Updates the service to state for handling system suspend. |
| void PrepareForSuspend(); |
| |
| // Exposes the profile to which the service is attached to subclasses. |
| Profile* profile() const { return profile_; } |
| |
| // Resets the Smart Lock state set by this service. |
| void ResetSmartLockState(); |
| |
| // Called by subclasses when remote devices allowed to unlock the screen |
| // are loaded for `account_id`. |
| void SetProximityAuthDevices( |
| const AccountId& account_id, |
| const multidevice::RemoteDeviceRefList& remote_devices, |
| absl::optional<multidevice::RemoteDeviceRef> local_device); |
| |
| void set_will_authenticate_using_easy_unlock( |
| bool will_authenticate_using_easy_unlock) { |
| will_authenticate_using_easy_unlock_ = will_authenticate_using_easy_unlock; |
| } |
| |
| void ShowChromebookAddedNotification(); |
| |
| // Fill in the UI with the state returned by GetInitialSmartLockState(). |
| void ShowInitialSmartLockState(); |
| |
| void ShowNotificationIfNewDevicePresent( |
| const std::set<std::string>& public_keys_before_sync, |
| const std::set<std::string>& public_keys_after_sync); |
| |
| // Called when ready to begin recording Smart Lock feature usage |
| // within Standard Feature Usage Logging (SFUL) framework. |
| void StartFeatureUsageMetrics(); |
| |
| // Called when ready to stop recording Smart Lock feature usage |
| // within SFUL framework. |
| void StopFeatureUsageMetrics(); |
| |
| // Checks whether Easy unlock should be running and updates app state. |
| void UpdateAppState(); |
| |
| void UseLoadedRemoteDevices( |
| const multidevice::RemoteDeviceRefList& remote_devices); |
| |
| bool will_authenticate_using_easy_unlock() const { |
| return will_authenticate_using_easy_unlock_; |
| } |
| |
| // True if the user just authenticated using Easy Unlock. Reset once |
| // the screen unlocks. Used to distinguish Easy Unlock-powered |
| // unlocks from password-based unlocks for metrics. |
| bool will_authenticate_using_easy_unlock_ = false; |
| |
| const raw_ptr<Profile, ExperimentalAsh> profile_; |
| raw_ptr<secure_channel::SecureChannelClient, ExperimentalAsh> |
| secure_channel_client_; |
| |
| ChromeProximityAuthClient proximity_auth_client_; |
| |
| absl::optional<SmartLockState> smart_lock_state_; |
| |
| // The handler for the current auth attempt. Set iff an auth attempt is in |
| // progress. |
| std::unique_ptr<EasyUnlockAuthAttempt> auth_attempt_; |
| |
| // Handles connecting, authenticating, and updating the UI on the lock |
| // screen. After a `RemoteDeviceRef` instance is provided, this object will |
| // handle the rest. |
| std::unique_ptr<proximity_auth::ProximityAuthSystem> proximity_auth_system_; |
| |
| // Monitors suspend and wake state of ChromeOS. |
| class PowerMonitor; |
| std::unique_ptr<PowerMonitor> power_monitor_; |
| |
| // Whether the service has been shut down. |
| bool shut_down_; |
| |
| // The timestamp for the most recent time when the lock screen was shown. The |
| // lock screen is typically shown when the user awakens their computer from |
| // sleep -- e.g. by opening the lid -- but can also be shown if the screen is |
| // locked but the computer does not go to sleep. |
| base::TimeTicks lock_screen_last_shown_timestamp_; |
| |
| // Manager responsible for handling the prefs used by proximity_auth classes. |
| std::unique_ptr<proximity_auth::ProximityAuthProfilePrefManager> |
| pref_manager_; |
| |
| // If a new RemoteDevice was synced while the screen is locked, we defer |
| // loading the RemoteDevice until the screen is unlocked. For security, |
| // this deferment prevents the lock screen from being changed by a network |
| // event. |
| bool deferring_device_load_ = false; |
| |
| // Responsible for showing all the notifications used for EasyUnlock. |
| std::unique_ptr<EasyUnlockNotificationController> notification_controller_; |
| |
| // Used to fetch local device and remote device data. |
| raw_ptr<device_sync::DeviceSyncClient, DanglingUntriaged | ExperimentalAsh> |
| device_sync_client_; |
| |
| // Used to determine the FeatureState of Smart Lock. |
| raw_ptr<multidevice_setup::MultiDeviceSetupClient, |
| DanglingUntriaged | ExperimentalAsh> |
| multidevice_setup_client_; |
| |
| // Tracks Smart Lock feature usage for the Standard Feature Usage Logging |
| // (SFUL) framework. |
| std::unique_ptr<SmartLockFeatureUsageMetrics> feature_usage_metrics_; |
| |
| // Stores the unlock keys for EasyUnlock before the current device sync, so we |
| // can compare it to the unlock keys after syncing. |
| std::vector<cryptauth::ExternalDeviceInfo> unlock_keys_before_sync_; |
| multidevice::RemoteDeviceRefList remote_device_unlock_keys_before_sync_; |
| |
| // True if the pairing changed notification was shown, so that the next time |
| // the Chromebook is unlocked, we can show the subsequent 'pairing applied' |
| // notification. |
| bool shown_pairing_changed_notification_ = false; |
| |
| base::WeakPtrFactory<EasyUnlockService> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_LOGIN_EASY_UNLOCK_EASY_UNLOCK_SERVICE_H_ |