Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2458)

Side by Side Diff: components/proximity_auth/unlock_manager.cc

Issue 1239193005: [Proximity Auth] Port the UnlockManager class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix destruction order in tests on ChromeOS Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "components/proximity_auth/unlock_manager.h"
6
7 #include "base/bind.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/client.h"
13 #include "components/proximity_auth/logging/logging.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"
18
19 #if defined(OS_CHROMEOS)
20 #include "chromeos/dbus/dbus_thread_manager.h"
21
22 using chromeos::DBusThreadManager;
23 #endif // defined(OS_CHROMEOS)
24
25 namespace proximity_auth {
26 namespace {
27
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;
31
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;
36
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;
44
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;
56 }
57
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;
69 }
70 }
71
72 NOTREACHED();
73 return metrics::RemoteSecuritySettingsState::UNKNOWN;
74 }
75
76 } // namespace
77
78 UnlockManager::UnlockManager(ScreenlockType screenlock_type,
79 scoped_ptr<ProximityMonitor> proximity_monitor,
80 ProximityAuthClient* proximity_auth_client)
81 : screenlock_type_(screenlock_type),
82 controller_(nullptr),
83 client_(nullptr),
84 proximity_monitor_(proximity_monitor.Pass()),
85 proximity_auth_client_(proximity_auth_client),
86 is_locked_(false),
87 is_attempting_auth_(false),
88 is_waking_up_(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
94 // JavaScript lines:
95 //
96 // chrome.screenlockPrivate.onAuthAttempted.addListener(
97 // this.onAuthAttempted_.bind(this));
98
99 ScreenlockBridge* screenlock_bridge = ScreenlockBridge::Get();
100 screenlock_bridge->AddObserver(this);
101 OnScreenLockedOrUnlocked(screenlock_bridge->IsLocked());
102
103 #if defined(OS_CHROMEOS)
104 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
105 #endif // defined(OS_CHROMEOS)
106 SetWakingUpState(true);
107
108 if (device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable()) {
109 device::BluetoothAdapterFactory::GetAdapter(
110 base::Bind(&UnlockManager::OnBluetoothAdapterInitialized,
111 weak_ptr_factory_.GetWeakPtr()));
112 }
113 }
114
115 UnlockManager::~UnlockManager() {
116 if (client_)
117 client_->RemoveObserver(this);
118
119 ScreenlockBridge::Get()->RemoveObserver(this);
120
121 #if defined(OS_CHROMEOS)
122 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
123 #endif // defined(OS_CHROMEOS)
124
125 if (bluetooth_adapter_)
126 bluetooth_adapter_->RemoveObserver(this);
127 }
128
129 bool UnlockManager::IsUnlockAllowed() {
130 return (remote_screenlock_state_ &&
131 *remote_screenlock_state_ == RemoteScreenlockState::UNLOCKED &&
132 controller_ &&
133 controller_->GetState() ==
134 Controller::State::SECURE_CHANNEL_ESTABLISHED &&
135 proximity_monitor_->IsUnlockAllowed() &&
136 (screenlock_type_ != ScreenlockType::SIGN_IN ||
137 (client_ && client_->SupportsSignIn())));
138 }
139
140 void UnlockManager::SetController(Controller* controller) {
141 if (client_) {
142 client_->RemoveObserver(this);
143 client_ = nullptr;
144 }
145
146 controller_ = controller;
147 if (controller_)
148 SetWakingUpState(true);
149
150 UpdateLockScreen();
151 }
152
153 void UnlockManager::OnControllerStateChanged() {
154 Controller::State state = controller_->GetState();
155 PA_LOG(INFO) << "[Unlock] Controller state changed: "
156 << static_cast<int>(state);
157
158 remote_screenlock_state_.reset();
159 if (state == Controller::State::SECURE_CHANNEL_ESTABLISHED) {
160 client_ = controller_->GetClient();
161 client_->AddObserver(this);
162 }
163
164 if (state == Controller::State::AUTHENTICATION_FAILED)
165 SetWakingUpState(false);
166
167 UpdateLockScreen();
168 }
169
170 void UnlockManager::OnUnlockEventSent(bool success) {
171 if (!is_attempting_auth_) {
172 PA_LOG(ERROR) << "[Unlock] Sent easy_unlock event, but no auth attempted.";
173 return;
174 }
175
176 if (sign_in_secret_ && success)
177 proximity_auth_client_->FinalizeSignin(*sign_in_secret_);
178
179 AcceptAuthAttempt(success);
180 }
181
182 void UnlockManager::OnRemoteStatusUpdate(
183 const RemoteStatusUpdate& status_update) {
184 PA_LOG(INFO) << "[Unlock] Status Update: ("
185 << "user_present=" << status_update.user_presence << ", "
186 << "secure_screen_lock="
187 << status_update.secure_screen_lock_state << ", "
188 << "trust_agent=" << status_update.trust_agent_state << ")";
189 metrics::RecordRemoteSecuritySettingsState(
190 GetRemoteSecuritySettingsState(status_update));
191
192 remote_screenlock_state_.reset(new RemoteScreenlockState(
193 GetScreenlockStateFromRemoteUpdate(status_update)));
194
195 // This also calls |UpdateLockScreen()|
196 SetWakingUpState(false);
197 }
198
199 void UnlockManager::OnDecryptResponse(scoped_ptr<std::string> decrypted_bytes) {
200 if (!is_attempting_auth_) {
201 PA_LOG(ERROR) << "[Unlock] Decrypt response received but not attempting "
202 << "auth.";
203 return;
204 }
205
206 if (!decrypted_bytes) {
207 PA_LOG(INFO) << "[Unlock] Failed to decrypt sign-in challenge.";
208 AcceptAuthAttempt(false);
209 } else {
210 sign_in_secret_ = decrypted_bytes.Pass();
211 client_->DispatchUnlockEvent();
212 }
213 }
214
215 void UnlockManager::OnUnlockResponse(bool success) {
216 if (!is_attempting_auth_) {
217 PA_LOG(ERROR) << "[Unlock] Unlock response received but not attempting "
218 << "auth.";
219 return;
220 }
221
222 PA_LOG(INFO) << "[Unlock] Unlock response from remote device: "
223 << (success ? "success" : "failure");
224 if (success)
225 client_->DispatchUnlockEvent();
226 else
227 AcceptAuthAttempt(false);
228 }
229
230 void UnlockManager::OnDisconnected() {
231 client_->RemoveObserver(this);
232 client_ = nullptr;
233 }
234
235 void UnlockManager::OnScreenDidLock(
236 ScreenlockBridge::LockHandler::ScreenType screen_type) {
237 OnScreenLockedOrUnlocked(true);
238 }
239
240 void UnlockManager::OnScreenDidUnlock(
241 ScreenlockBridge::LockHandler::ScreenType screen_type) {
242 OnScreenLockedOrUnlocked(false);
243 }
244
245 void UnlockManager::OnFocusedUserChanged(const std::string& user_id) {}
246
247 void UnlockManager::OnScreenLockedOrUnlocked(bool is_locked) {
248 // TODO(tengs): Chrome will only start connecting to the phone when
249 // the screen is locked, for privacy reasons. We should reinvestigate
250 // this behaviour if we want automatic locking.
251 if (is_locked && bluetooth_adapter_ && bluetooth_adapter_->IsPowered() &&
252 controller_ &&
253 controller_->GetState() == Controller::State::FINDING_CONNECTION) {
254 SetWakingUpState(true);
255 }
256
257 is_locked_ = is_locked;
258 UpdateProximityMonitorState();
259 }
260
261 void UnlockManager::OnBluetoothAdapterInitialized(
262 scoped_refptr<device::BluetoothAdapter> adapter) {
263 bluetooth_adapter_ = adapter;
264 bluetooth_adapter_->AddObserver(this);
265 }
266
267 void UnlockManager::AdapterPresentChanged(device::BluetoothAdapter* adapter,
268 bool present) {
269 UpdateLockScreen();
270 }
271
272 void UnlockManager::AdapterPoweredChanged(device::BluetoothAdapter* adapter,
273 bool powered) {
274 UpdateLockScreen();
275 }
276
277 #if defined(OS_CHROMEOS)
278 void UnlockManager::SuspendDone(const base::TimeDelta& sleep_duration) {
279 SetWakingUpState(true);
280 }
281 #endif // defined(OS_CHROMEOS)
282
283 void UnlockManager::OnAuthAttempted(
284 ScreenlockBridge::LockHandler::AuthType auth_type) {
285 if (is_attempting_auth_) {
286 PA_LOG(INFO) << "[Unlock] Already attempting auth.";
287 return;
288 }
289
290 if (auth_type != ScreenlockBridge::LockHandler::USER_CLICK)
291 return;
292
293 is_attempting_auth_ = true;
294
295 if (!controller_) {
296 PA_LOG(ERROR) << "[Unlock] No controller active when auth is attempted";
297 AcceptAuthAttempt(false);
298 UpdateLockScreen();
299 return;
300 }
301
302 if (!IsUnlockAllowed()) {
303 AcceptAuthAttempt(false);
304 UpdateLockScreen();
305 return;
306 }
307
308 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
309 FROM_HERE,
310 base::Bind(&UnlockManager::AcceptAuthAttempt,
311 reject_auth_attempt_weak_ptr_factory_.GetWeakPtr(), false),
312 base::TimeDelta::FromSeconds(kAuthAttemptTimeoutSecs));
313
314 if (screenlock_type_ == ScreenlockType::SIGN_IN) {
315 SendSignInChallenge();
316 } else {
317 if (client_->SupportsSignIn()) {
318 client_->RequestUnlock();
319 } else {
320 PA_LOG(INFO) << "[Unlock] Protocol v3.1 not supported, skipping "
321 << "request_unlock.";
322 client_->DispatchUnlockEvent();
323 }
324 }
325 }
326
327 void UnlockManager::SendSignInChallenge() {
328 // TODO(isherman): Implement.
329 NOTIMPLEMENTED();
330 }
331
332 ScreenlockState UnlockManager::GetScreenlockState() {
333 if (!controller_ || controller_->GetState() == Controller::State::STOPPED)
334 return ScreenlockState::INACTIVE;
335
336 if (IsUnlockAllowed())
337 return ScreenlockState::AUTHENTICATED;
338
339 if (controller_->GetState() == Controller::State::AUTHENTICATION_FAILED)
340 return ScreenlockState::PHONE_NOT_AUTHENTICATED;
341
342 if (is_waking_up_)
343 return ScreenlockState::BLUETOOTH_CONNECTING;
344
345 if (!bluetooth_adapter_ || !bluetooth_adapter_->IsPowered())
346 return ScreenlockState::NO_BLUETOOTH;
347
348 if (screenlock_type_ == ScreenlockType::SIGN_IN && client_ &&
349 !client_->SupportsSignIn())
350 return ScreenlockState::PHONE_UNSUPPORTED;
351
352 // If the RSSI is too low, then the remote device is nowhere near the local
353 // device. This message should take priority over messages about screen lock
354 // states.
355 if (!proximity_monitor_->IsUnlockAllowed() &&
356 !proximity_monitor_->IsInRssiRange())
357 return ScreenlockState::RSSI_TOO_LOW;
358
359 if (remote_screenlock_state_) {
360 switch (*remote_screenlock_state_) {
361 case RemoteScreenlockState::DISABLED:
362 return ScreenlockState::PHONE_NOT_LOCKABLE;
363
364 case RemoteScreenlockState::LOCKED:
365 if (proximity_monitor_->GetStrategy() ==
366 ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER &&
367 !proximity_monitor_->IsUnlockAllowed()) {
368 return ScreenlockState::PHONE_LOCKED_AND_TX_POWER_TOO_HIGH;
369 }
370 return ScreenlockState::PHONE_LOCKED;
371
372 case RemoteScreenlockState::UNKNOWN:
373 return ScreenlockState::PHONE_UNSUPPORTED;
374
375 case RemoteScreenlockState::UNLOCKED:
376 // Handled by the code below.
377 break;
378 }
379 }
380
381 if (!proximity_monitor_->IsUnlockAllowed()) {
382 ProximityMonitor::Strategy strategy = proximity_monitor_->GetStrategy();
383 if (strategy != ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER) {
384 // CHECK_RSSI should have been handled above, and no other states should
385 // prevent unlocking.
386 PA_LOG(ERROR) << "[Unlock] Invalid ProximityMonitor strategy: "
387 << static_cast<int>(strategy);
388 return ScreenlockState::NO_PHONE;
389 }
390 return ScreenlockState::TX_POWER_TOO_HIGH;
391 }
392
393 return ScreenlockState::NO_PHONE;
394 }
395
396 void UnlockManager::UpdateLockScreen() {
397 UpdateProximityMonitorState();
398
399 ScreenlockState new_state = GetScreenlockState();
400 if (screenlock_state_ == new_state)
401 return;
402
403 proximity_auth_client_->UpdateScreenlockState(new_state);
404 screenlock_state_ = new_state;
405 }
406
407 void UnlockManager::UpdateProximityMonitorState() {
408 if (is_locked_ && controller_ &&
409 controller_->GetState() ==
410 Controller::State::SECURE_CHANNEL_ESTABLISHED) {
411 proximity_monitor_->Start();
412 } else {
413 proximity_monitor_->Stop();
414 }
415 }
416
417 void UnlockManager::SetWakingUpState(bool is_waking_up) {
418 is_waking_up_ = is_waking_up;
419
420 // Clear the waking up state after a timeout.
421 clear_waking_up_state_weak_ptr_factory_.InvalidateWeakPtrs();
422 if (is_waking_up_) {
423 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
424 FROM_HERE,
425 base::Bind(&UnlockManager::SetWakingUpState,
426 clear_waking_up_state_weak_ptr_factory_.GetWeakPtr(), false),
427 base::TimeDelta::FromSeconds(kWakingUpDurationSecs));
428 }
429
430 UpdateLockScreen();
431 }
432
433 void UnlockManager::AcceptAuthAttempt(bool should_accept) {
434 if (!is_attempting_auth_)
435 return;
436
437 // Cancel the pending task to time out the auth attempt.
438 reject_auth_attempt_weak_ptr_factory_.InvalidateWeakPtrs();
439
440 if (should_accept)
441 proximity_monitor_->RecordProximityMetricsOnAuthSuccess();
442
443 is_attempting_auth_ = false;
444 proximity_auth_client_->FinalizeUnlock(should_accept);
445 }
446
447 UnlockManager::RemoteScreenlockState
448 UnlockManager::GetScreenlockStateFromRemoteUpdate(RemoteStatusUpdate update) {
449 switch (update.secure_screen_lock_state) {
450 case SECURE_SCREEN_LOCK_DISABLED:
451 return RemoteScreenlockState::DISABLED;
452
453 case SECURE_SCREEN_LOCK_ENABLED:
454 if (update.user_presence == USER_PRESENT)
455 return RemoteScreenlockState::UNLOCKED;
456
457 return RemoteScreenlockState::LOCKED;
458
459 case SECURE_SCREEN_LOCK_STATE_UNKNOWN:
460 return RemoteScreenlockState::UNKNOWN;
461 }
462
463 NOTREACHED();
464 return RemoteScreenlockState::UNKNOWN;
465 }
466
467 } // namespace proximity_auth
OLDNEW
« no previous file with comments | « components/proximity_auth/unlock_manager.h ('k') | components/proximity_auth/unlock_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698