1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_ASH_COMPONENTS_PROXIMITY_AUTH_UNLOCK_MANAGER_IMPL_H_
#define CHROMEOS_ASH_COMPONENTS_PROXIMITY_AUTH_UNLOCK_MANAGER_IMPL_H_
#include "ash/public/cpp/smartlock_state.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chromeos/ash/components/proximity_auth/messenger_observer.h"
#include "chromeos/ash/components/proximity_auth/proximity_auth_system.h"
#include "chromeos/ash/components/proximity_auth/proximity_monitor_observer.h"
#include "chromeos/ash/components/proximity_auth/remote_device_life_cycle.h"
#include "chromeos/ash/components/proximity_auth/remote_status_update.h"
#include "chromeos/ash/components/proximity_auth/screenlock_bridge.h"
#include "chromeos/ash/components/proximity_auth/smart_lock_metrics_recorder.h"
#include "chromeos/ash/components/proximity_auth/unlock_manager.h"
#include "chromeos/ash/services/secure_channel/public/mojom/secure_channel.mojom.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "device/bluetooth/bluetooth_adapter.h"
namespace base {
class OneShotTimer;
} // namespace base
namespace proximity_auth {
class Messenger;
class ProximityAuthClient;
class ProximityMonitor;
// The unlock manager is responsible for controlling the lock screen UI based on
// the authentication status of the registered remote devices.
class UnlockManagerImpl : public UnlockManager,
public MessengerObserver,
public ProximityMonitorObserver,
public chromeos::PowerManagerClient::Observer,
public device::BluetoothAdapter::Observer,
public RemoteDeviceLifeCycle::Observer {
public:
// The |proximity_auth_client| is not owned and should outlive the constructed
// unlock manager.
explicit UnlockManagerImpl(ProximityAuthClient* proximity_auth_client);
UnlockManagerImpl(const UnlockManagerImpl&) = delete;
UnlockManagerImpl& operator=(const UnlockManagerImpl&) = delete;
~UnlockManagerImpl() override;
// UnlockManager:
bool IsUnlockAllowed() override;
void SetRemoteDeviceLifeCycle(RemoteDeviceLifeCycle* life_cycle) override;
void OnAuthAttempted(mojom::AuthType auth_type) override;
void CancelConnectionAttempt() override;
std::string GetLastRemoteStatusUnlockForLogging() override;
protected:
// Creates a ProximityMonitor instance for the given |connection|.
// Exposed for testing.
virtual std::unique_ptr<ProximityMonitor> CreateProximityMonitor(
RemoteDeviceLifeCycle* life_cycle);
private:
friend class ProximityAuthUnlockManagerImplTest;
// The possible lock screen states for the remote device.
enum class RemoteScreenlockState {
UNKNOWN,
UNLOCKED,
DISABLED,
LOCKED,
PRIMARY_USER_ABSENT,
};
// This enum is tied directly to the
// SmartLockGetRemoteStatusResultFailureReason UMA enum defined in
// //tools/metrics/histograms/metadata/cross_device/enums.xml, and should
// always reflect it (do not change one without changing the other). Entries
// should be never modified or deleted. Only additions possible.
//
// LINT.IfChange(SmartLockGetRemoteStatusResultFailureReason)
enum class GetRemoteStatusResultFailureReason {
kCanceledBluetoothDisabled = 0,
kDeprecatedTimedOutCouldNotEstablishAuthenticatedChannel = 1,
kTimedOutDidNotReceiveRemoteStatusUpdate = 2,
kDeprecatedUserEnteredPasswordWhileBluetoothDisabled = 3,
kCanceledUserEnteredPassword = 4,
kAuthenticatedChannelDropped = 5,
kMaxValue = kAuthenticatedChannelDropped
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/cross_device/enums.xml:SmartLockGetRemoteStatusResultFailureReason)
// MessengerObserver:
void OnUnlockEventSent(bool success) override;
void OnRemoteStatusUpdate(const RemoteStatusUpdate& status_update) override;
void OnUnlockResponse(bool success) override;
void OnDisconnected() override;
// ProximityMonitorObserver:
void OnProximityStateChanged() override;
// Called when the screenlock state changes.
void OnScreenLockedOrUnlocked(bool is_locked);
// Called when the Bluetooth adapter is initialized.
void OnBluetoothAdapterInitialized(
scoped_refptr<device::BluetoothAdapter> adapter);
// device::BluetoothAdapter::Observer:
void AdapterPresentChanged(device::BluetoothAdapter* adapter,
bool present) override;
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) override;
// chromeos::PowerManagerClient::Observer:
void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
void SuspendDone(base::TimeDelta sleep_duration) override;
// RemoteDeviceLifeCycle::Observer:
void OnLifeCycleStateChanged(RemoteDeviceLifeCycle::State old_state,
RemoteDeviceLifeCycle::State new_state) override;
// Returns true if the BluetoothAdapter is present and powered.
bool IsBluetoothPresentAndPowered() const;
// TODO(crbug.com/986896): Waiting a certain time, after resume, before
// trusting the presence and power values returned by BluetoothAdapter is
// necessary because the BluetoothAdapter returns incorrect values directly
// after resume, and does not return correct values until about 1-2 seconds
// later. Remove this function once the bug is resolved.
//
// This function returns true if the BluetoothAdapter is still resuming from
// suspension, indicating that its returned presence and power values cannot
// yet be trusted.
bool IsBluetoothAdapterRecoveringFromSuspend() const;
// Called once BluetoothAdapter has recovered after resuming from suspend,
// meaning its presence and power values can be trusted again. This method
// checks if Bluetooth is enabled; if it is not, it cancels the initial scan.
void OnBluetoothAdapterPresentAndPoweredChanged();
// If the RemoteDeviceLifeCycle is available, ensure it is started (but only
// if Bluetooth is available).
void AttemptToStartRemoteDeviceLifecycle();
// Returns the current state for the Smart Lock UI.
ash::SmartLockState GetSmartLockState();
// Updates the lock screen based on the manager's current state.
void UpdateLockScreen();
// Activates or deactivates the proximity monitor, as appropriate given the
// current state of |this| unlock manager.
void UpdateProximityMonitorState();
// Sets if the "initial scan" is in progress. This state factors into what is
// shown to the user. See |is_performing_initial_scan_| for more.
void SetIsPerformingInitialScan(bool is_performing_initial_scan);
// Accepts or rejects the current auth attempt according to |error|. Accepts
// if and only if |error| is empty. If the auth attempt is accepted, unlocks
// the screen.
void FinalizeAuthAttempt(
const std::optional<
SmartLockMetricsRecorder::SmartLockAuthResultFailureReason>& error);
// Failed to create a connection to the host during the "initial scan". See
// |is_performing_initial_scan_| for more.
void OnInitialScanTimeout();
// Returns the screen lock state corresponding to the given remote |status|
// update.
RemoteScreenlockState GetScreenlockStateFromRemoteUpdate(
RemoteStatusUpdate update);
// Returns the Messenger instance associated with |life_cycle_|. This function
// will return nullptr if |life_cycle_| is not set or the remote device is not
// yet authenticated.
Messenger* GetMessenger();
// Records UMA performance metrics for the first remote status (regardless of
// whether it's unlockable) being received.
void RecordFirstRemoteStatusReceived(bool unlockable);
// Records a UMA metric for the first status shown to the user as well
// as performance metrics for how long it takes to show that first status
// (regardless of whether it's unlockable/green).
void RecordFirstStatusShownToUser(ash::SmartLockState new_state);
// Clears the timers for beginning a scan and fetching remote status.
void ResetPerformanceMetricsTimestamps();
void SetBluetoothSuspensionRecoveryTimerForTesting(
std::unique_ptr<base::OneShotTimer> timer);
// For recording metrics.
void RecordGetRemoteStatusResultSuccess(bool success = true);
void RecordGetRemoteStatusResultFailure(
GetRemoteStatusResultFailureReason failure_reason);
std::string GetRemoteStatusResultFailureReasonToString(
GetRemoteStatusResultFailureReason reason);
// Used to call into the embedder. Expected to outlive |this| instance.
raw_ptr<ProximityAuthClient> proximity_auth_client_;
// Starts running after resuming from suspension, and fires once enough time
// has elapsed such that the BluetoothAdapter's presence and power values can
// be trusted again. To be removed once https://crbug.com/986896 is fixed.
std::unique_ptr<base::OneShotTimer> bluetooth_suspension_recovery_timer_;
// The Bluetooth adapter. Null if there is no adapter present on the local
// device.
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
// Tracks whether the remote device is currently in close enough proximity to
// the local device to allow unlocking.
std::unique_ptr<ProximityMonitor> proximity_monitor_;
// Whether the user is present at the remote device. Unset if no remote status
// update has yet been received.
std::unique_ptr<RemoteScreenlockState> remote_screenlock_state_;
// Controls the proximity auth flow logic for a remote device. Not owned, and
// expcted to outlive |this| instance.
raw_ptr<RemoteDeviceLifeCycle> life_cycle_ = nullptr;
// True if the manager is currently processing a user-initiated authentication
// attempt, which is initiated when the user pod is clicked.
bool is_attempting_auth_ = false;
// If true, either the lock screen was just shown (after resuming from
// suspend, or directly locking the screen), or the focused user pod was
// switched. It becomes false if the phone is found, something goes wrong
// while searching for the phone, or the initial scan times out (at which
// point the user visually sees an indication that the phone cannot be found).
// Though this field becomes false after this timeout, Smart Lock continues
// to scan for the phone until the user unlocks the screen.
bool is_performing_initial_scan_ = false;
// True if a secure connection is currently active with the host.
bool is_bluetooth_connection_to_phone_active_ = false;
// TODO(crbug.com/986896): For a short time window after resuming from
// suspension, BluetoothAdapter returns incorrect presence and power values.
// This field acts as a cache in case we need to check those values during
// that time window when the device resumes. Remove this field once the bug
// is fixed.
bool was_bluetooth_present_and_powered_before_last_suspend_ = false;
// True only if the remote device has responded with a remote status, either
// "unlockable" or otherwise.
bool has_received_first_remote_status_ = false;
// True only if the user has been shown a Smart Lock status and tooltip,
// either "unlockable" (green) or otherwise (yellow).
bool has_user_been_shown_first_status_ = false;
// The state of the current screen lock UI.
ash::SmartLockState smartlock_state_ = ash::SmartLockState::kInactive;
// The timestamp of when the lock or login screen is shown to the user. Begins
// when the screen is locked, the system is rebooted, the clamshell lid is
// opened, or another user pod is switched to on the login screen.
base::Time show_lock_screen_time_;
// The timestamp of when UnlockManager begins to perform the initial scan for
// the requested remote device of the provided RemoteDeviceLifeCycle. Usually
// begins right after |show_lock_screen_time_|, unless Bluetooth is disabled.
// If Bluetooth is re-enabled, it also begins.
base::Time initial_scan_start_time_;
// The timestamp of when UnlockManager successfully establishes a secure
// connection to the requested remote device of the provided
// RemoteDeviceLifeCycle, and begins to try to fetch its "remote status".
base::Time attempt_get_remote_status_start_time_;
// Stores the last value emitted to the
// SmartLock.GetRemoteStatus.Unlock(.Failure) metrics. Should be |nullopt|
// until the first time GetRemoteStatus succeeds or fails.
std::optional<bool> get_remote_status_unlock_success_;
std::optional<GetRemoteStatusResultFailureReason>
get_remote_status_unlock_failure_reason_;
// Used to track if the "initial scan" has timed out. See
// |is_performing_initial_scan_| for more.
base::WeakPtrFactory<UnlockManagerImpl>
initial_scan_timeout_weak_ptr_factory_{this};
// Used to reject auth attempts after a timeout. An in-progress auth attempt
// blocks the sign-in screen UI, so it's important to prevent the auth attempt
// from blocking the UI in case a step in the code path hangs.
base::WeakPtrFactory<UnlockManagerImpl> reject_auth_attempt_weak_ptr_factory_{
this};
// Used to vend all other weak pointers.
base::WeakPtrFactory<UnlockManagerImpl> weak_ptr_factory_{this};
};
} // namespace proximity_auth
#endif // CHROMEOS_ASH_COMPONENTS_PROXIMITY_AUTH_UNLOCK_MANAGER_IMPL_H_
|