blob: 2e984827808456a0b1253c7fc71b6b34ba78bd35 [file] [log] [blame]
// 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_