1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/proximity_auth/unlock_manager.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/time/time.h"
12 #include "components/proximity_auth/logging/logging.h"
13 #include "components/proximity_auth/messenger.h"
14 #include "components/proximity_auth/metrics.h"
15 #include "components/proximity_auth/proximity_auth_client.h"
16 #include "components/proximity_auth/proximity_monitor.h"
17 #include "device/bluetooth/bluetooth_adapter_factory.h"
19 #if defined(OS_CHROMEOS)
20 #include "chromeos/dbus/dbus_thread_manager.h"
22 using chromeos::DBusThreadManager
;
23 #endif // defined(OS_CHROMEOS)
25 namespace proximity_auth
{
28 // The maximum amount of time, in seconds, that the unlock manager can stay in
29 // the 'waking up' state after resuming from sleep.
30 const int kWakingUpDurationSecs
= 5;
32 // The limit, in seconds, on the elapsed time for an auth attempt. If an auth
33 // attempt exceeds this limit, it will time out and be rejected. This is
34 // provided as a failsafe, in case something goes wrong.
35 const int kAuthAttemptTimeoutSecs
= 5;
37 // Returns the remote device's security settings state, for metrics,
38 // corresponding to a remote status update.
39 metrics::RemoteSecuritySettingsState
GetRemoteSecuritySettingsState(
40 const RemoteStatusUpdate
& status_update
) {
41 switch (status_update
.secure_screen_lock_state
) {
42 case SECURE_SCREEN_LOCK_STATE_UNKNOWN
:
43 return metrics::RemoteSecuritySettingsState::UNKNOWN
;
45 case SECURE_SCREEN_LOCK_DISABLED
:
46 switch (status_update
.trust_agent_state
) {
47 case TRUST_AGENT_UNSUPPORTED
:
48 return metrics::RemoteSecuritySettingsState::
49 SCREEN_LOCK_DISABLED_TRUST_AGENT_UNSUPPORTED
;
50 case TRUST_AGENT_DISABLED
:
51 return metrics::RemoteSecuritySettingsState::
52 SCREEN_LOCK_DISABLED_TRUST_AGENT_DISABLED
;
53 case TRUST_AGENT_ENABLED
:
54 return metrics::RemoteSecuritySettingsState::
55 SCREEN_LOCK_DISABLED_TRUST_AGENT_ENABLED
;
58 case SECURE_SCREEN_LOCK_ENABLED
:
59 switch (status_update
.trust_agent_state
) {
60 case TRUST_AGENT_UNSUPPORTED
:
61 return metrics::RemoteSecuritySettingsState::
62 SCREEN_LOCK_ENABLED_TRUST_AGENT_UNSUPPORTED
;
63 case TRUST_AGENT_DISABLED
:
64 return metrics::RemoteSecuritySettingsState::
65 SCREEN_LOCK_ENABLED_TRUST_AGENT_DISABLED
;
66 case TRUST_AGENT_ENABLED
:
67 return metrics::RemoteSecuritySettingsState::
68 SCREEN_LOCK_ENABLED_TRUST_AGENT_ENABLED
;
73 return metrics::RemoteSecuritySettingsState::UNKNOWN
;
78 UnlockManager::UnlockManager(ScreenlockType screenlock_type
,
79 scoped_ptr
<ProximityMonitor
> proximity_monitor
,
80 ProximityAuthClient
* proximity_auth_client
)
81 : screenlock_type_(screenlock_type
),
84 proximity_monitor_(proximity_monitor
.Pass()),
85 proximity_auth_client_(proximity_auth_client
),
87 is_attempting_auth_(false),
89 screenlock_state_(ScreenlockState::INACTIVE
),
90 clear_waking_up_state_weak_ptr_factory_(this),
91 reject_auth_attempt_weak_ptr_factory_(this),
92 weak_ptr_factory_(this) {
93 // TODO(isherman): Register for auth attempt notifications, equivalent to the
96 // chrome.screenlockPrivate.onAuthAttempted.addListener(
97 // this.onAuthAttempted_.bind(this));
99 ScreenlockBridge
* screenlock_bridge
= ScreenlockBridge::Get();
100 screenlock_bridge
->AddObserver(this);
101 OnScreenLockedOrUnlocked(screenlock_bridge
->IsLocked());
103 #if defined(OS_CHROMEOS)
104 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
105 #endif // defined(OS_CHROMEOS)
106 SetWakingUpState(true);
108 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
109 device::BluetoothAdapterFactory::GetAdapter(
110 base::Bind(&UnlockManager::OnBluetoothAdapterInitialized
,
111 weak_ptr_factory_
.GetWeakPtr()));
115 UnlockManager::~UnlockManager() {
117 messenger_
->RemoveObserver(this);
119 ScreenlockBridge::Get()->RemoveObserver(this);
121 #if defined(OS_CHROMEOS)
122 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
123 #endif // defined(OS_CHROMEOS)
125 if (bluetooth_adapter_
)
126 bluetooth_adapter_
->RemoveObserver(this);
129 bool UnlockManager::IsUnlockAllowed() {
130 return (remote_screenlock_state_
&&
131 *remote_screenlock_state_
== RemoteScreenlockState::UNLOCKED
&&
133 life_cycle_
->GetState() ==
134 RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
&&
135 proximity_monitor_
->IsUnlockAllowed() &&
136 (screenlock_type_
!= ScreenlockType::SIGN_IN
||
137 (messenger_
&& messenger_
->SupportsSignIn())));
140 void UnlockManager::SetRemoteDeviceLifeCycle(
141 RemoteDeviceLifeCycle
* life_cycle
) {
143 messenger_
->RemoveObserver(this);
144 messenger_
= nullptr;
147 life_cycle_
= life_cycle
;
149 SetWakingUpState(true);
154 void UnlockManager::OnLifeCycleStateChanged() {
155 RemoteDeviceLifeCycle::State state
= life_cycle_
->GetState();
156 PA_LOG(INFO
) << "[Unlock] RemoteDeviceLifeCycle state changed: "
157 << static_cast<int>(state
);
159 remote_screenlock_state_
.reset();
160 if (state
== RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
) {
161 messenger_
= life_cycle_
->GetMessenger();
162 messenger_
->AddObserver(this);
165 if (state
== RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED
)
166 SetWakingUpState(false);
171 void UnlockManager::OnUnlockEventSent(bool success
) {
172 if (!is_attempting_auth_
) {
173 PA_LOG(ERROR
) << "[Unlock] Sent easy_unlock event, but no auth attempted.";
177 if (sign_in_secret_
&& success
)
178 proximity_auth_client_
->FinalizeSignin(*sign_in_secret_
);
180 AcceptAuthAttempt(success
);
183 void UnlockManager::OnRemoteStatusUpdate(
184 const RemoteStatusUpdate
& status_update
) {
185 PA_LOG(INFO
) << "[Unlock] Status Update: ("
186 << "user_present=" << status_update
.user_presence
<< ", "
187 << "secure_screen_lock="
188 << status_update
.secure_screen_lock_state
<< ", "
189 << "trust_agent=" << status_update
.trust_agent_state
<< ")";
190 metrics::RecordRemoteSecuritySettingsState(
191 GetRemoteSecuritySettingsState(status_update
));
193 remote_screenlock_state_
.reset(new RemoteScreenlockState(
194 GetScreenlockStateFromRemoteUpdate(status_update
)));
196 // This also calls |UpdateLockScreen()|
197 SetWakingUpState(false);
200 void UnlockManager::OnDecryptResponse(scoped_ptr
<std::string
> decrypted_bytes
) {
201 if (!is_attempting_auth_
) {
202 PA_LOG(ERROR
) << "[Unlock] Decrypt response received but not attempting "
207 if (!decrypted_bytes
) {
208 PA_LOG(INFO
) << "[Unlock] Failed to decrypt sign-in challenge.";
209 AcceptAuthAttempt(false);
211 sign_in_secret_
= decrypted_bytes
.Pass();
212 messenger_
->DispatchUnlockEvent();
216 void UnlockManager::OnUnlockResponse(bool success
) {
217 if (!is_attempting_auth_
) {
218 PA_LOG(ERROR
) << "[Unlock] Unlock response received but not attempting "
223 PA_LOG(INFO
) << "[Unlock] Unlock response from remote device: "
224 << (success
? "success" : "failure");
226 messenger_
->DispatchUnlockEvent();
228 AcceptAuthAttempt(false);
231 void UnlockManager::OnDisconnected() {
232 messenger_
->RemoveObserver(this);
233 messenger_
= nullptr;
236 void UnlockManager::OnScreenDidLock(
237 ScreenlockBridge::LockHandler::ScreenType screen_type
) {
238 OnScreenLockedOrUnlocked(true);
241 void UnlockManager::OnScreenDidUnlock(
242 ScreenlockBridge::LockHandler::ScreenType screen_type
) {
243 OnScreenLockedOrUnlocked(false);
246 void UnlockManager::OnFocusedUserChanged(const std::string
& user_id
) {}
248 void UnlockManager::OnScreenLockedOrUnlocked(bool is_locked
) {
249 // TODO(tengs): Chrome will only start connecting to the phone when
250 // the screen is locked, for privacy reasons. We should reinvestigate
251 // this behaviour if we want automatic locking.
252 if (is_locked
&& bluetooth_adapter_
&& bluetooth_adapter_
->IsPowered() &&
254 life_cycle_
->GetState() ==
255 RemoteDeviceLifeCycle::State::FINDING_CONNECTION
) {
256 SetWakingUpState(true);
259 is_locked_
= is_locked
;
260 UpdateProximityMonitorState();
263 void UnlockManager::OnBluetoothAdapterInitialized(
264 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
265 bluetooth_adapter_
= adapter
;
266 bluetooth_adapter_
->AddObserver(this);
269 void UnlockManager::AdapterPresentChanged(device::BluetoothAdapter
* adapter
,
274 void UnlockManager::AdapterPoweredChanged(device::BluetoothAdapter
* adapter
,
279 #if defined(OS_CHROMEOS)
280 void UnlockManager::SuspendDone(const base::TimeDelta
& sleep_duration
) {
281 SetWakingUpState(true);
283 #endif // defined(OS_CHROMEOS)
285 void UnlockManager::OnAuthAttempted(
286 ScreenlockBridge::LockHandler::AuthType auth_type
) {
287 if (is_attempting_auth_
) {
288 PA_LOG(INFO
) << "[Unlock] Already attempting auth.";
292 if (auth_type
!= ScreenlockBridge::LockHandler::USER_CLICK
)
295 is_attempting_auth_
= true;
298 PA_LOG(ERROR
) << "[Unlock] No life_cycle active when auth is attempted";
299 AcceptAuthAttempt(false);
304 if (!IsUnlockAllowed()) {
305 AcceptAuthAttempt(false);
310 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
312 base::Bind(&UnlockManager::AcceptAuthAttempt
,
313 reject_auth_attempt_weak_ptr_factory_
.GetWeakPtr(), false),
314 base::TimeDelta::FromSeconds(kAuthAttemptTimeoutSecs
));
316 if (screenlock_type_
== ScreenlockType::SIGN_IN
) {
317 SendSignInChallenge();
319 if (messenger_
->SupportsSignIn()) {
320 messenger_
->RequestUnlock();
322 PA_LOG(INFO
) << "[Unlock] Protocol v3.1 not supported, skipping "
323 << "request_unlock.";
324 messenger_
->DispatchUnlockEvent();
329 void UnlockManager::SendSignInChallenge() {
330 // TODO(isherman): Implement.
334 ScreenlockState
UnlockManager::GetScreenlockState() {
336 life_cycle_
->GetState() == RemoteDeviceLifeCycle::State::STOPPED
)
337 return ScreenlockState::INACTIVE
;
339 if (IsUnlockAllowed())
340 return ScreenlockState::AUTHENTICATED
;
342 if (life_cycle_
->GetState() ==
343 RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED
)
344 return ScreenlockState::PHONE_NOT_AUTHENTICATED
;
347 return ScreenlockState::BLUETOOTH_CONNECTING
;
349 if (!bluetooth_adapter_
|| !bluetooth_adapter_
->IsPowered())
350 return ScreenlockState::NO_BLUETOOTH
;
352 if (screenlock_type_
== ScreenlockType::SIGN_IN
&& messenger_
&&
353 !messenger_
->SupportsSignIn())
354 return ScreenlockState::PHONE_UNSUPPORTED
;
356 // If the RSSI is too low, then the remote device is nowhere near the local
357 // device. This message should take priority over messages about screen lock
359 if (!proximity_monitor_
->IsUnlockAllowed() &&
360 !proximity_monitor_
->IsInRssiRange())
361 return ScreenlockState::RSSI_TOO_LOW
;
363 if (remote_screenlock_state_
) {
364 switch (*remote_screenlock_state_
) {
365 case RemoteScreenlockState::DISABLED
:
366 return ScreenlockState::PHONE_NOT_LOCKABLE
;
368 case RemoteScreenlockState::LOCKED
:
369 if (proximity_monitor_
->GetStrategy() ==
370 ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
&&
371 !proximity_monitor_
->IsUnlockAllowed()) {
372 return ScreenlockState::PHONE_LOCKED_AND_TX_POWER_TOO_HIGH
;
374 return ScreenlockState::PHONE_LOCKED
;
376 case RemoteScreenlockState::UNKNOWN
:
377 return ScreenlockState::PHONE_UNSUPPORTED
;
379 case RemoteScreenlockState::UNLOCKED
:
380 // Handled by the code below.
385 if (!proximity_monitor_
->IsUnlockAllowed()) {
386 ProximityMonitor::Strategy strategy
= proximity_monitor_
->GetStrategy();
387 if (strategy
!= ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
) {
388 // CHECK_RSSI should have been handled above, and no other states should
389 // prevent unlocking.
390 PA_LOG(ERROR
) << "[Unlock] Invalid ProximityMonitor strategy: "
391 << static_cast<int>(strategy
);
392 return ScreenlockState::NO_PHONE
;
394 return ScreenlockState::TX_POWER_TOO_HIGH
;
397 return ScreenlockState::NO_PHONE
;
400 void UnlockManager::UpdateLockScreen() {
401 UpdateProximityMonitorState();
403 ScreenlockState new_state
= GetScreenlockState();
404 if (screenlock_state_
== new_state
)
407 proximity_auth_client_
->UpdateScreenlockState(new_state
);
408 screenlock_state_
= new_state
;
411 void UnlockManager::UpdateProximityMonitorState() {
412 if (is_locked_
&& life_cycle_
&&
413 life_cycle_
->GetState() ==
414 RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
) {
415 proximity_monitor_
->Start();
417 proximity_monitor_
->Stop();
421 void UnlockManager::SetWakingUpState(bool is_waking_up
) {
422 is_waking_up_
= is_waking_up
;
424 // Clear the waking up state after a timeout.
425 clear_waking_up_state_weak_ptr_factory_
.InvalidateWeakPtrs();
427 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
429 base::Bind(&UnlockManager::SetWakingUpState
,
430 clear_waking_up_state_weak_ptr_factory_
.GetWeakPtr(), false),
431 base::TimeDelta::FromSeconds(kWakingUpDurationSecs
));
437 void UnlockManager::AcceptAuthAttempt(bool should_accept
) {
438 if (!is_attempting_auth_
)
441 // Cancel the pending task to time out the auth attempt.
442 reject_auth_attempt_weak_ptr_factory_
.InvalidateWeakPtrs();
445 proximity_monitor_
->RecordProximityMetricsOnAuthSuccess();
447 is_attempting_auth_
= false;
448 proximity_auth_client_
->FinalizeUnlock(should_accept
);
451 UnlockManager::RemoteScreenlockState
452 UnlockManager::GetScreenlockStateFromRemoteUpdate(RemoteStatusUpdate update
) {
453 switch (update
.secure_screen_lock_state
) {
454 case SECURE_SCREEN_LOCK_DISABLED
:
455 return RemoteScreenlockState::DISABLED
;
457 case SECURE_SCREEN_LOCK_ENABLED
:
458 if (update
.user_presence
== USER_PRESENT
)
459 return RemoteScreenlockState::UNLOCKED
;
461 return RemoteScreenlockState::LOCKED
;
463 case SECURE_SCREEN_LOCK_STATE_UNKNOWN
:
464 return RemoteScreenlockState::UNKNOWN
;
468 return RemoteScreenlockState::UNKNOWN
;
471 } // namespace proximity_auth