Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_service.cc
blobde94c7d26146c48d7bd5a4136c8f0c486e1bb4f7
1 // Copyright 2014 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 "chrome/browser/signin/easy_unlock_service.h"
7 #include "apps/app_lifetime_monitor.h"
8 #include "apps/app_lifetime_monitor_factory.h"
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/guid.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/prefs/pref_registry_simple.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/prefs/scoped_user_pref_update.h"
17 #include "base/sys_info.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "base/version.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/signin/chrome_proximity_auth_client.h"
25 #include "chrome/browser/signin/easy_unlock_app_manager.h"
26 #include "chrome/browser/signin/easy_unlock_service_factory.h"
27 #include "chrome/browser/signin/easy_unlock_service_observer.h"
28 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
29 #include "chrome/browser/signin/signin_manager_factory.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/chrome_version_info.h"
32 #include "chrome/common/extensions/extension_constants.h"
33 #include "chrome/common/pref_names.h"
34 #include "components/pref_registry/pref_registry_syncable.h"
35 #include "components/proximity_auth/ble/proximity_auth_ble_system.h"
36 #include "components/proximity_auth/cryptauth/cryptauth_client_impl.h"
37 #include "components/proximity_auth/cryptauth/cryptauth_device_manager.h"
38 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h"
39 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
40 #include "components/proximity_auth/screenlock_bridge.h"
41 #include "components/proximity_auth/switches.h"
42 #include "components/signin/core/browser/profile_oauth2_token_service.h"
43 #include "components/signin/core/browser/signin_manager.h"
44 #include "components/user_manager/user.h"
45 #include "device/bluetooth/bluetooth_adapter.h"
46 #include "device/bluetooth/bluetooth_adapter_factory.h"
48 #if defined(OS_CHROMEOS)
49 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
50 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
51 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
52 #include "chrome/browser/chromeos/login/easy_unlock/secure_message_delegate_chromeos.h"
53 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
54 #include "chrome/browser/chromeos/profiles/profile_helper.h"
55 #include "chromeos/dbus/dbus_thread_manager.h"
56 #include "chromeos/dbus/power_manager_client.h"
57 #include "components/user_manager/user_manager.h"
58 #endif
60 #if defined(OS_WIN)
61 #include "base/win/windows_version.h"
62 #endif
64 using proximity_auth::ScreenlockState;
66 namespace {
68 enum BluetoothType {
69 BT_NO_ADAPTER,
70 BT_NORMAL,
71 BT_LOW_ENERGY_CAPABLE,
72 BT_MAX_TYPE
75 PrefService* GetLocalState() {
76 return g_browser_process ? g_browser_process->local_state() : NULL;
79 } // namespace
81 EasyUnlockService::UserSettings::UserSettings()
82 : require_close_proximity(false) {
85 EasyUnlockService::UserSettings::~UserSettings() {
88 // static
89 EasyUnlockService* EasyUnlockService::Get(Profile* profile) {
90 return EasyUnlockServiceFactory::GetForBrowserContext(profile);
93 // static
94 EasyUnlockService* EasyUnlockService::GetForUser(
95 const user_manager::User& user) {
96 #if defined(OS_CHROMEOS)
97 Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(&user);
98 if (!profile)
99 return NULL;
100 return EasyUnlockService::Get(profile);
101 #else
102 return NULL;
103 #endif
106 // static
107 bool EasyUnlockService::IsSignInEnabled() {
108 return !base::CommandLine::ForCurrentProcess()->HasSwitch(
109 proximity_auth::switches::kDisableEasyUnlock);
112 class EasyUnlockService::BluetoothDetector
113 : public device::BluetoothAdapter::Observer,
114 public apps::AppLifetimeMonitor::Observer {
115 public:
116 explicit BluetoothDetector(EasyUnlockService* service)
117 : service_(service),
118 weak_ptr_factory_(this) {
119 apps::AppLifetimeMonitorFactory::GetForProfile(service_->profile())
120 ->AddObserver(this);
123 ~BluetoothDetector() override {
124 if (adapter_.get())
125 adapter_->RemoveObserver(this);
126 apps::AppLifetimeMonitorFactory::GetForProfile(service_->profile())
127 ->RemoveObserver(this);
130 void Initialize() {
131 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
132 return;
134 device::BluetoothAdapterFactory::GetAdapter(
135 base::Bind(&BluetoothDetector::OnAdapterInitialized,
136 weak_ptr_factory_.GetWeakPtr()));
139 bool IsPresent() const { return adapter_.get() && adapter_->IsPresent(); }
141 // device::BluetoothAdapter::Observer:
142 void AdapterPresentChanged(device::BluetoothAdapter* adapter,
143 bool present) override {
144 service_->OnBluetoothAdapterPresentChanged();
147 device::BluetoothAdapter* getAdapter() {
148 return adapter_.get();
151 private:
152 void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) {
153 adapter_ = adapter;
154 adapter_->AddObserver(this);
155 service_->OnBluetoothAdapterPresentChanged();
157 #if !defined(OS_CHROMEOS)
158 // Bluetooth detection causes serious performance degradations on Mac
159 // and possibly other platforms as well: http://crbug.com/467316
160 // Since this feature is currently only offered for ChromeOS we just
161 // turn it off on other platforms once the inforamtion about the
162 // adapter has been gathered and reported.
163 // TODO(bcwhite,xiyuan): Revisit when non-chromeos platforms are supported.
164 adapter_->RemoveObserver(this);
165 adapter_ = NULL;
166 #else
167 // TODO(tengs): At the moment, there is no way for Bluetooth discoverability
168 // to be turned on except through the Easy Unlock setup. If we step on any
169 // toes in the future then we need to revisit this guard.
170 if (adapter_->IsDiscoverable())
171 TurnOffBluetoothDiscoverability();
172 #endif // !defined(OS_CHROMEOS)
175 // apps::AppLifetimeMonitor::Observer:
176 void OnAppDeactivated(Profile* profile, const std::string& app_id) override {
177 // TODO(tengs): Refactor the lifetime management to EasyUnlockAppManager.
178 if (app_id == extension_misc::kEasyUnlockAppId)
179 TurnOffBluetoothDiscoverability();
182 void OnAppStop(Profile* profile, const std::string& app_id) override {
183 // TODO(tengs): Refactor the lifetime management to EasyUnlockAppManager.
184 if (app_id == extension_misc::kEasyUnlockAppId)
185 TurnOffBluetoothDiscoverability();
188 void TurnOffBluetoothDiscoverability() {
189 if (adapter_) {
190 adapter_->SetDiscoverable(
191 false, base::Bind(&base::DoNothing), base::Bind(&base::DoNothing));
195 // Owner of this class and should out-live this class.
196 EasyUnlockService* service_;
197 scoped_refptr<device::BluetoothAdapter> adapter_;
198 base::WeakPtrFactory<BluetoothDetector> weak_ptr_factory_;
200 DISALLOW_COPY_AND_ASSIGN(BluetoothDetector);
203 #if defined(OS_CHROMEOS)
204 class EasyUnlockService::PowerMonitor
205 : public chromeos::PowerManagerClient::Observer {
206 public:
207 explicit PowerMonitor(EasyUnlockService* service)
208 : service_(service),
209 waking_up_(false),
210 weak_ptr_factory_(this) {
211 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
212 AddObserver(this);
215 ~PowerMonitor() override {
216 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
217 RemoveObserver(this);
220 // Called when the remote device has been authenticated to record the time
221 // delta from waking up. No time will be recorded if the start-up time has
222 // already been recorded or if the system never went to sleep previously.
223 void RecordStartUpTime() {
224 if (wake_up_time_.is_null())
225 return;
226 UMA_HISTOGRAM_MEDIUM_TIMES(
227 "EasyUnlock.StartupTimeFromSuspend",
228 base::Time::Now() - wake_up_time_);
229 wake_up_time_ = base::Time();
232 bool waking_up() const { return waking_up_; }
234 private:
235 // chromeos::PowerManagerClient::Observer:
236 void SuspendImminent() override { service_->PrepareForSuspend(); }
238 void SuspendDone(const base::TimeDelta& sleep_duration) override {
239 waking_up_ = true;
240 wake_up_time_ = base::Time::Now();
241 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
242 FROM_HERE,
243 base::Bind(&PowerMonitor::ResetWakingUp,
244 weak_ptr_factory_.GetWeakPtr()),
245 base::TimeDelta::FromSeconds(5));
246 service_->OnSuspendDone();
247 service_->UpdateAppState();
248 // Note that |this| may get deleted after |UpdateAppState| is called.
251 void ResetWakingUp() {
252 waking_up_ = false;
253 service_->UpdateAppState();
256 EasyUnlockService* service_;
257 bool waking_up_;
258 base::Time wake_up_time_;
259 base::WeakPtrFactory<PowerMonitor> weak_ptr_factory_;
261 DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
263 #endif
265 EasyUnlockService::EasyUnlockService(Profile* profile)
266 : profile_(profile),
267 proximity_auth_client_(profile),
268 bluetooth_detector_(new BluetoothDetector(this)),
269 shut_down_(false),
270 tpm_key_checked_(false),
271 weak_ptr_factory_(this) {
274 EasyUnlockService::~EasyUnlockService() {
277 // static
278 void EasyUnlockService::RegisterProfilePrefs(
279 user_prefs::PrefRegistrySyncable* registry) {
280 registry->RegisterBooleanPref(prefs::kEasyUnlockAllowed, true);
281 registry->RegisterBooleanPref(prefs::kEasyUnlockEnabled, false);
282 registry->RegisterDictionaryPref(prefs::kEasyUnlockPairing,
283 new base::DictionaryValue());
284 registry->RegisterBooleanPref(
285 prefs::kEasyUnlockProximityRequired,
286 false,
287 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
289 proximity_auth::CryptAuthDeviceManager::RegisterPrefs(registry);
290 proximity_auth::CryptAuthEnrollmentManager::RegisterPrefs(registry);
292 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
293 proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery))
294 proximity_auth::ProximityAuthBleSystem::RegisterPrefs(registry);
297 // static
298 void EasyUnlockService::RegisterPrefs(PrefRegistrySimple* registry) {
299 registry->RegisterStringPref(prefs::kEasyUnlockDeviceId, std::string());
300 registry->RegisterDictionaryPref(prefs::kEasyUnlockHardlockState);
301 registry->RegisterDictionaryPref(prefs::kEasyUnlockLocalStateUserPrefs);
302 #if defined(OS_CHROMEOS)
303 EasyUnlockTpmKeyManager::RegisterLocalStatePrefs(registry);
304 #endif
307 // static
308 void EasyUnlockService::ResetLocalStateForUser(const std::string& user_id) {
309 DCHECK(!user_id.empty());
311 PrefService* local_state = GetLocalState();
312 if (!local_state)
313 return;
315 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
316 update->RemoveWithoutPathExpansion(user_id, NULL);
318 #if defined(OS_CHROMEOS)
319 EasyUnlockTpmKeyManager::ResetLocalStateForUser(user_id);
320 #endif
323 // static
324 EasyUnlockService::UserSettings EasyUnlockService::GetUserSettings(
325 const std::string& user_id) {
326 DCHECK(!user_id.empty());
327 UserSettings user_settings;
329 PrefService* local_state = GetLocalState();
330 if (!local_state)
331 return user_settings;
333 const base::DictionaryValue* all_user_prefs_dict =
334 local_state->GetDictionary(prefs::kEasyUnlockLocalStateUserPrefs);
335 if (!all_user_prefs_dict)
336 return user_settings;
338 const base::DictionaryValue* user_prefs_dict;
339 if (!all_user_prefs_dict->GetDictionaryWithoutPathExpansion(user_id,
340 &user_prefs_dict))
341 return user_settings;
343 user_prefs_dict->GetBooleanWithoutPathExpansion(
344 prefs::kEasyUnlockProximityRequired,
345 &user_settings.require_close_proximity);
347 return user_settings;
350 // static
351 std::string EasyUnlockService::GetDeviceId() {
352 PrefService* local_state = GetLocalState();
353 if (!local_state)
354 return std::string();
356 std::string device_id = local_state->GetString(prefs::kEasyUnlockDeviceId);
357 if (device_id.empty()) {
358 device_id = base::GenerateGUID();
359 local_state->SetString(prefs::kEasyUnlockDeviceId, device_id);
361 return device_id;
364 void EasyUnlockService::Initialize(
365 scoped_ptr<EasyUnlockAppManager> app_manager) {
366 app_manager_ = app_manager.Pass();
367 app_manager_->EnsureReady(
368 base::Bind(&EasyUnlockService::InitializeOnAppManagerReady,
369 weak_ptr_factory_.GetWeakPtr()));
372 bool EasyUnlockService::IsAllowed() const {
373 if (shut_down_)
374 return false;
376 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
377 proximity_auth::switches::kDisableEasyUnlock)) {
378 return false;
381 if (!IsAllowedInternal())
382 return false;
384 #if defined(OS_CHROMEOS)
385 if (!bluetooth_detector_->IsPresent())
386 return false;
388 return true;
389 #else
390 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
391 return false;
392 #endif
395 bool EasyUnlockService::IsEnabled() const {
396 // The feature is enabled iff there are any paired devices.
397 const base::ListValue* devices = GetRemoteDevices();
398 return devices && !devices->empty();
401 void EasyUnlockService::OpenSetupApp() {
402 app_manager_->LaunchSetup();
405 void EasyUnlockService::SetHardlockState(
406 EasyUnlockScreenlockStateHandler::HardlockState state) {
407 const std::string user_id = GetUserEmail();
408 if (user_id.empty())
409 return;
411 if (state == GetHardlockState())
412 return;
414 SetHardlockStateForUser(user_id, state);
417 EasyUnlockScreenlockStateHandler::HardlockState
418 EasyUnlockService::GetHardlockState() const {
419 EasyUnlockScreenlockStateHandler::HardlockState state;
420 if (GetPersistedHardlockState(&state))
421 return state;
423 return EasyUnlockScreenlockStateHandler::NO_HARDLOCK;
426 bool EasyUnlockService::GetPersistedHardlockState(
427 EasyUnlockScreenlockStateHandler::HardlockState* state) const {
428 std::string user_id = GetUserEmail();
429 if (user_id.empty())
430 return false;
432 PrefService* local_state = GetLocalState();
433 if (!local_state)
434 return false;
436 const base::DictionaryValue* dict =
437 local_state->GetDictionary(prefs::kEasyUnlockHardlockState);
438 int state_int;
439 if (dict && dict->GetIntegerWithoutPathExpansion(user_id, &state_int)) {
440 *state =
441 static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state_int);
442 return true;
445 return false;
448 void EasyUnlockService::ShowInitialUserState() {
449 if (!GetScreenlockStateHandler())
450 return;
452 EasyUnlockScreenlockStateHandler::HardlockState state;
453 bool has_persisted_state = GetPersistedHardlockState(&state);
454 if (!has_persisted_state)
455 return;
457 if (state == EasyUnlockScreenlockStateHandler::NO_HARDLOCK) {
458 // Show connecting icon early when there is a persisted non hardlock state.
459 UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING);
460 } else {
461 screenlock_state_handler_->MaybeShowHardlockUI();
465 EasyUnlockScreenlockStateHandler*
466 EasyUnlockService::GetScreenlockStateHandler() {
467 if (!IsAllowed())
468 return NULL;
469 if (!screenlock_state_handler_) {
470 screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler(
471 GetUserEmail(), GetHardlockState(),
472 proximity_auth::ScreenlockBridge::Get()));
474 return screenlock_state_handler_.get();
477 bool EasyUnlockService::UpdateScreenlockState(ScreenlockState state) {
478 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
479 if (!handler)
480 return false;
482 handler->ChangeState(state);
484 if (state == ScreenlockState::AUTHENTICATED) {
485 #if defined(OS_CHROMEOS)
486 if (power_monitor_)
487 power_monitor_->RecordStartUpTime();
488 #endif
489 } else if (auth_attempt_.get()) {
490 // Clean up existing auth attempt if we can no longer authenticate the
491 // remote device.
492 auth_attempt_.reset();
494 if (!handler->InStateValidOnRemoteAuthFailure())
495 HandleAuthFailure(GetUserEmail());
498 FOR_EACH_OBSERVER(
499 EasyUnlockServiceObserver, observers_, OnScreenlockStateChanged(state));
500 return true;
503 ScreenlockState EasyUnlockService::GetScreenlockState() {
504 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
505 if (!handler)
506 return ScreenlockState::INACTIVE;
508 return handler->state();
511 void EasyUnlockService::AttemptAuth(const std::string& user_id) {
512 AttemptAuth(user_id, AttemptAuthCallback());
515 void EasyUnlockService::AttemptAuth(const std::string& user_id,
516 const AttemptAuthCallback& callback) {
517 const EasyUnlockAuthAttempt::Type auth_attempt_type =
518 GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK
519 : EasyUnlockAuthAttempt::TYPE_SIGNIN;
520 const std::string user_email = GetUserEmail();
521 if (user_email.empty()) {
522 LOG(ERROR) << "Empty user email. Refresh token might go bad.";
523 if (!callback.is_null()) {
524 const bool kFailure = false;
525 callback.Run(auth_attempt_type, kFailure, user_id, std::string(),
526 std::string());
528 return;
531 CHECK_EQ(GetUserEmail(), user_id);
533 auth_attempt_.reset(new EasyUnlockAuthAttempt(app_manager_.get(), user_id,
534 auth_attempt_type, callback));
535 if (!auth_attempt_->Start())
536 auth_attempt_.reset();
539 void EasyUnlockService::FinalizeUnlock(bool success) {
540 if (!auth_attempt_.get())
541 return;
543 this->OnWillFinalizeUnlock(success);
544 auth_attempt_->FinalizeUnlock(GetUserEmail(), success);
545 auth_attempt_.reset();
546 // TODO(isherman): If observing screen unlock events, is there a race
547 // condition in terms of reading the service's state vs. the app setting the
548 // state?
550 // Make sure that the lock screen is updated on failure.
551 if (!success) {
552 RecordEasyUnlockScreenUnlockEvent(EASY_UNLOCK_FAILURE);
553 HandleAuthFailure(GetUserEmail());
557 void EasyUnlockService::FinalizeSignin(const std::string& key) {
558 if (!auth_attempt_.get())
559 return;
560 std::string wrapped_secret = GetWrappedSecret();
561 if (!wrapped_secret.empty())
562 auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key);
563 auth_attempt_.reset();
565 // Processing empty key is equivalent to auth cancellation. In this case the
566 // signin request will not actually be processed by login stack, so the lock
567 // screen state should be set from here.
568 if (key.empty())
569 HandleAuthFailure(GetUserEmail());
572 void EasyUnlockService::HandleAuthFailure(const std::string& user_id) {
573 if (user_id != GetUserEmail())
574 return;
576 if (!screenlock_state_handler_.get())
577 return;
579 screenlock_state_handler_->SetHardlockState(
580 EasyUnlockScreenlockStateHandler::LOGIN_FAILED);
583 void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() {
584 #if defined(OS_CHROMEOS)
585 std::string user_id = GetUserEmail();
586 if (user_id.empty())
587 return;
589 const base::ListValue* device_list = GetRemoteDevices();
590 std::set<std::string> paired_devices;
591 if (device_list) {
592 chromeos::EasyUnlockDeviceKeyDataList parsed_paired;
593 chromeos::EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList(
594 *device_list, &parsed_paired);
595 for (const auto& device_key_data : parsed_paired)
596 paired_devices.insert(device_key_data.psk);
598 if (paired_devices.empty()) {
599 SetHardlockState(EasyUnlockScreenlockStateHandler::NO_PAIRING);
600 return;
603 // No need to compare if a change is already recorded.
604 if (GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_CHANGED ||
605 GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_ADDED) {
606 return;
609 chromeos::EasyUnlockKeyManager* key_manager =
610 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
611 DCHECK(key_manager);
613 key_manager->GetDeviceDataList(
614 chromeos::UserContext(user_id),
615 base::Bind(&EasyUnlockService::OnCryptohomeKeysFetchedForChecking,
616 weak_ptr_factory_.GetWeakPtr(),
617 user_id,
618 paired_devices));
619 #endif
622 void EasyUnlockService::SetTrialRun() {
623 DCHECK_EQ(GetType(), TYPE_REGULAR);
625 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
626 if (handler)
627 handler->SetTrialRun();
630 void EasyUnlockService::RecordClickOnLockIcon() {
631 if (screenlock_state_handler_)
632 screenlock_state_handler_->RecordClickOnLockIcon();
635 void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) {
636 observers_.AddObserver(observer);
639 void EasyUnlockService::RemoveObserver(EasyUnlockServiceObserver* observer) {
640 observers_.RemoveObserver(observer);
643 PrefService* EasyUnlockService::GetPrefService() {
644 return profile()->GetPrefs();
647 scoped_ptr<proximity_auth::SecureMessageDelegate>
648 EasyUnlockService::CreateSecureMessageDelegate() {
649 #if defined(OS_CHROMEOS)
650 return make_scoped_ptr(new chromeos::SecureMessageDelegateChromeOS());
651 #else
652 return nullptr;
653 #endif
656 scoped_ptr<proximity_auth::CryptAuthClientFactory>
657 EasyUnlockService::CreateCryptAuthClientFactory() {
658 return make_scoped_ptr(new proximity_auth::CryptAuthClientFactoryImpl(
659 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
660 SigninManagerFactory::GetForProfile(profile())
661 ->GetAuthenticatedAccountId(),
662 profile()->GetRequestContext(), GetDeviceClassifier()));
665 cryptauth::DeviceClassifier EasyUnlockService::GetDeviceClassifier() {
666 cryptauth::DeviceClassifier device_classifier;
668 #if defined(OS_CHROMEOS)
669 int32 major_version, minor_version, bugfix_version;
670 // TODO(tengs): base::OperatingSystemVersionNumbers only works for ChromeOS.
671 // We need to get different numbers for other platforms.
672 base::SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
673 &bugfix_version);
674 device_classifier.set_device_os_version_code(major_version);
675 device_classifier.set_device_type(cryptauth::CHROME);
676 #endif
678 chrome::VersionInfo version_info;
679 const std::vector<uint32_t>& version_components =
680 base::Version(version_info.Version()).components();
681 if (version_components.size() > 0)
682 device_classifier.set_device_software_version_code(version_components[0]);
684 device_classifier.set_device_software_package(version_info.Name());
685 return device_classifier;
688 void EasyUnlockService::Shutdown() {
689 if (shut_down_)
690 return;
691 shut_down_ = true;
693 ShutdownInternal();
695 ResetScreenlockState();
696 bluetooth_detector_.reset();
697 #if defined(OS_CHROMEOS)
698 power_monitor_.reset();
699 #endif
701 weak_ptr_factory_.InvalidateWeakPtrs();
704 void EasyUnlockService::ReloadAppAndLockScreen() {
705 // Make sure lock screen state set by the extension gets reset.
706 ResetScreenlockState();
707 app_manager_->ReloadApp();
708 NotifyUserUpdated();
711 void EasyUnlockService::UpdateAppState() {
712 if (IsAllowed()) {
713 EnsureTpmKeyPresentIfNeeded();
714 app_manager_->LoadApp();
715 NotifyUserUpdated();
717 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
718 proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery) &&
719 GetType() == EasyUnlockService::TYPE_REGULAR &&
720 !proximity_auth_ble_system_) {
721 proximity_auth_ble_system_.reset(
722 new proximity_auth::ProximityAuthBleSystem(
723 proximity_auth::ScreenlockBridge::Get(), &proximity_auth_client_,
724 CreateCryptAuthClientFactory(), profile_->GetPrefs()));
727 #if defined(OS_CHROMEOS)
728 if (!power_monitor_)
729 power_monitor_.reset(new PowerMonitor(this));
730 #endif
731 } else {
732 bool bluetooth_waking_up = false;
733 #if defined(OS_CHROMEOS)
734 // If the service is not allowed due to bluetooth not being detected just
735 // after system suspend is done, give bluetooth more time to be detected
736 // before disabling the app (and resetting screenlock state).
737 bluetooth_waking_up =
738 power_monitor_.get() && power_monitor_->waking_up() &&
739 !bluetooth_detector_->IsPresent();
740 #endif
742 if (!bluetooth_waking_up) {
743 app_manager_->DisableAppIfLoaded();
744 ResetScreenlockState();
745 proximity_auth_ble_system_.reset();
746 #if defined(OS_CHROMEOS)
747 power_monitor_.reset();
748 #endif
753 void EasyUnlockService::DisableAppWithoutResettingScreenlockState() {
754 app_manager_->DisableAppIfLoaded();
757 void EasyUnlockService::NotifyUserUpdated() {
758 std::string user_id = GetUserEmail();
759 if (user_id.empty())
760 return;
762 // Notify the easy unlock app that the user info changed.
763 bool logged_in = GetType() == TYPE_REGULAR;
764 bool data_ready = logged_in || GetRemoteDevices() != NULL;
765 app_manager_->SendUserUpdatedEvent(user_id, logged_in, data_ready);
768 void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
769 FOR_EACH_OBSERVER(
770 EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged());
773 void EasyUnlockService::ResetScreenlockState() {
774 screenlock_state_handler_.reset();
775 auth_attempt_.reset();
778 void EasyUnlockService::SetScreenlockHardlockedState(
779 EasyUnlockScreenlockStateHandler::HardlockState state) {
780 if (screenlock_state_handler_)
781 screenlock_state_handler_->SetHardlockState(state);
782 if (state != EasyUnlockScreenlockStateHandler::NO_HARDLOCK)
783 auth_attempt_.reset();
786 void EasyUnlockService::InitializeOnAppManagerReady() {
787 CHECK(app_manager_.get());
789 InitializeInternal();
790 bluetooth_detector_->Initialize();
793 void EasyUnlockService::OnBluetoothAdapterPresentChanged() {
794 UpdateAppState();
796 // Whether we've already passed Bluetooth availability information to UMA.
797 // This is static because there may be multiple instances and we want to
798 // report this system-level stat only once per run of Chrome.
799 static bool bluetooth_adapter_has_been_reported = false;
801 if (!bluetooth_adapter_has_been_reported) {
802 bluetooth_adapter_has_been_reported = true;
803 int bttype = BT_NO_ADAPTER;
804 if (bluetooth_detector_->IsPresent()) {
805 bttype = BT_LOW_ENERGY_CAPABLE;
806 #if defined(OS_WIN)
807 if (base::win::GetVersion() < base::win::VERSION_WIN8) {
808 bttype = BT_NORMAL;
810 #endif
812 UMA_HISTOGRAM_ENUMERATION(
813 "EasyUnlock.BluetoothAvailability", bttype, BT_MAX_TYPE);
817 void EasyUnlockService::SetHardlockStateForUser(
818 const std::string& user_id,
819 EasyUnlockScreenlockStateHandler::HardlockState state) {
820 DCHECK(!user_id.empty());
822 PrefService* local_state = GetLocalState();
823 if (!local_state)
824 return;
826 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
827 update->SetIntegerWithoutPathExpansion(user_id, static_cast<int>(state));
829 if (GetUserEmail() == user_id)
830 SetScreenlockHardlockedState(state);
833 EasyUnlockAuthEvent EasyUnlockService::GetPasswordAuthEvent() const {
834 DCHECK(IsEnabled());
836 if (GetHardlockState() != EasyUnlockScreenlockStateHandler::NO_HARDLOCK) {
837 switch (GetHardlockState()) {
838 case EasyUnlockScreenlockStateHandler::NO_HARDLOCK:
839 NOTREACHED();
840 return EASY_UNLOCK_AUTH_EVENT_COUNT;
841 case EasyUnlockScreenlockStateHandler::NO_PAIRING:
842 return PASSWORD_ENTRY_NO_PAIRING;
843 case EasyUnlockScreenlockStateHandler::USER_HARDLOCK:
844 return PASSWORD_ENTRY_USER_HARDLOCK;
845 case EasyUnlockScreenlockStateHandler::PAIRING_CHANGED:
846 return PASSWORD_ENTRY_PAIRING_CHANGED;
847 case EasyUnlockScreenlockStateHandler::LOGIN_FAILED:
848 return PASSWORD_ENTRY_LOGIN_FAILED;
849 case EasyUnlockScreenlockStateHandler::PAIRING_ADDED:
850 return PASSWORD_ENTRY_PAIRING_ADDED;
852 } else if (!screenlock_state_handler()) {
853 return PASSWORD_ENTRY_NO_SCREENLOCK_STATE_HANDLER;
854 } else {
855 switch (screenlock_state_handler()->state()) {
856 case ScreenlockState::INACTIVE:
857 return PASSWORD_ENTRY_SERVICE_NOT_ACTIVE;
858 case ScreenlockState::NO_BLUETOOTH:
859 return PASSWORD_ENTRY_NO_BLUETOOTH;
860 case ScreenlockState::BLUETOOTH_CONNECTING:
861 return PASSWORD_ENTRY_BLUETOOTH_CONNECTING;
862 case ScreenlockState::NO_PHONE:
863 return PASSWORD_ENTRY_NO_PHONE;
864 case ScreenlockState::PHONE_NOT_AUTHENTICATED:
865 return PASSWORD_ENTRY_PHONE_NOT_AUTHENTICATED;
866 case ScreenlockState::PHONE_LOCKED:
867 return PASSWORD_ENTRY_PHONE_LOCKED;
868 case ScreenlockState::PHONE_NOT_LOCKABLE:
869 return PASSWORD_ENTRY_PHONE_NOT_LOCKABLE;
870 case ScreenlockState::PHONE_UNSUPPORTED:
871 return PASSWORD_ENTRY_PHONE_UNSUPPORTED;
872 case ScreenlockState::RSSI_TOO_LOW:
873 return PASSWORD_ENTRY_RSSI_TOO_LOW;
874 case ScreenlockState::TX_POWER_TOO_HIGH:
875 return PASSWORD_ENTRY_TX_POWER_TOO_HIGH;
876 case ScreenlockState::PHONE_LOCKED_AND_TX_POWER_TOO_HIGH:
877 return PASSWORD_ENTRY_PHONE_LOCKED_AND_TX_POWER_TOO_HIGH;
878 case ScreenlockState::AUTHENTICATED:
879 return PASSWORD_ENTRY_WITH_AUTHENTICATED_PHONE;
883 NOTREACHED();
884 return EASY_UNLOCK_AUTH_EVENT_COUNT;
887 #if defined(OS_CHROMEOS)
888 void EasyUnlockService::OnCryptohomeKeysFetchedForChecking(
889 const std::string& user_id,
890 const std::set<std::string> paired_devices,
891 bool success,
892 const chromeos::EasyUnlockDeviceKeyDataList& key_data_list) {
893 DCHECK(!user_id.empty() && !paired_devices.empty());
895 if (!success) {
896 SetHardlockStateForUser(user_id,
897 EasyUnlockScreenlockStateHandler::NO_PAIRING);
898 return;
901 std::set<std::string> devices_in_cryptohome;
902 for (const auto& device_key_data : key_data_list)
903 devices_in_cryptohome.insert(device_key_data.psk);
905 if (paired_devices != devices_in_cryptohome ||
906 GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) {
907 SetHardlockStateForUser(
908 user_id,
909 devices_in_cryptohome.empty()
910 ? EasyUnlockScreenlockStateHandler::PAIRING_ADDED
911 : EasyUnlockScreenlockStateHandler::PAIRING_CHANGED);
914 #endif
916 void EasyUnlockService::PrepareForSuspend() {
917 app_manager_->DisableAppIfLoaded();
918 if (screenlock_state_handler_ && screenlock_state_handler_->IsActive())
919 UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING);
922 void EasyUnlockService::EnsureTpmKeyPresentIfNeeded() {
923 if (tpm_key_checked_ || GetType() != TYPE_REGULAR || GetUserEmail().empty() ||
924 GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) {
925 return;
928 #if defined(OS_CHROMEOS)
929 // If this is called before the session is started, the chances are Chrome
930 // is restarting in order to apply user flags. Don't check TPM keys in this
931 // case.
932 if (!user_manager::UserManager::Get() ||
933 !user_manager::UserManager::Get()->IsSessionStarted())
934 return;
936 // TODO(tbarzic): Set check_private_key only if previous sign-in attempt
937 // failed.
938 EasyUnlockTpmKeyManagerFactory::GetInstance()->Get(profile_)
939 ->PrepareTpmKey(true /* check_private_key */,
940 base::Closure());
941 #endif // defined(OS_CHROMEOS)
943 tpm_key_checked_ = true;