File: unlock_manager_impl.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (305 lines) | stat: -rw-r--r-- 13,556 bytes parent folder | download | duplicates (7)
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_