Home | History | Annotate | Download | only in signin
      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.
      4 
      5 #include "chrome/browser/signin/easy_unlock_service.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/command_line.h"
      9 #include "base/logging.h"
     10 #include "base/metrics/field_trial.h"
     11 #include "base/prefs/pref_registry_simple.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/prefs/scoped_user_pref_update.h"
     14 #include "base/thread_task_runner_handle.h"
     15 #include "base/time/time.h"
     16 #include "base/values.h"
     17 #include "chrome/browser/browser_process.h"
     18 #include "chrome/browser/extensions/component_loader.h"
     19 #include "chrome/browser/extensions/extension_service.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/signin/easy_unlock_auth_attempt.h"
     22 #include "chrome/browser/signin/easy_unlock_service_factory.h"
     23 #include "chrome/browser/signin/easy_unlock_service_observer.h"
     24 #include "chrome/browser/signin/screenlock_bridge.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "chrome/common/extensions/api/easy_unlock_private.h"
     27 #include "chrome/common/extensions/extension_constants.h"
     28 #include "chrome/common/pref_names.h"
     29 #include "components/pref_registry/pref_registry_syncable.h"
     30 #include "components/user_manager/user.h"
     31 #include "device/bluetooth/bluetooth_adapter.h"
     32 #include "device/bluetooth/bluetooth_adapter_factory.h"
     33 #include "extensions/browser/event_router.h"
     34 #include "extensions/browser/extension_registry.h"
     35 #include "extensions/browser/extension_system.h"
     36 #include "extensions/common/one_shot_event.h"
     37 #include "grit/browser_resources.h"
     38 
     39 #if defined(OS_CHROMEOS)
     40 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
     41 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
     42 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     43 #include "chromeos/chromeos_switches.h"
     44 #include "chromeos/dbus/dbus_thread_manager.h"
     45 #include "chromeos/dbus/power_manager_client.h"
     46 #endif
     47 
     48 namespace {
     49 
     50 extensions::ComponentLoader* GetComponentLoader(
     51     content::BrowserContext* context) {
     52   extensions::ExtensionSystem* extension_system =
     53       extensions::ExtensionSystem::Get(context);
     54   ExtensionService* extension_service = extension_system->extension_service();
     55   return extension_service->component_loader();
     56 }
     57 
     58 PrefService* GetLocalState() {
     59   return g_browser_process ? g_browser_process->local_state() : NULL;
     60 }
     61 
     62 }  // namespace
     63 
     64 // static
     65 EasyUnlockService* EasyUnlockService::Get(Profile* profile) {
     66   return EasyUnlockServiceFactory::GetForProfile(profile);
     67 }
     68 
     69 // static
     70 EasyUnlockService* EasyUnlockService::GetForUser(
     71     const user_manager::User& user) {
     72 #if defined(OS_CHROMEOS)
     73   Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(&user);
     74   if (!profile)
     75     return NULL;
     76   return EasyUnlockService::Get(profile);
     77 #else
     78   return NULL;
     79 #endif
     80 }
     81 
     82 // static
     83 bool EasyUnlockService::IsSignInEnabled() {
     84 #if defined(OS_CHROMEOS)
     85   const std::string group_name =
     86       base::FieldTrialList::FindFullName("EasySignIn");
     87 
     88   if (CommandLine::ForCurrentProcess()->HasSwitch(
     89           chromeos::switches::kDisableEasySignin)) {
     90     return false;
     91   }
     92 
     93   return group_name == "Enable";
     94 #else
     95   return false;
     96 #endif
     97 }
     98 
     99 class EasyUnlockService::BluetoothDetector
    100     : public device::BluetoothAdapter::Observer {
    101  public:
    102   explicit BluetoothDetector(EasyUnlockService* service)
    103       : service_(service),
    104         weak_ptr_factory_(this) {
    105   }
    106 
    107   virtual ~BluetoothDetector() {
    108     if (adapter_.get())
    109       adapter_->RemoveObserver(this);
    110   }
    111 
    112   void Initialize() {
    113     if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
    114       return;
    115 
    116     device::BluetoothAdapterFactory::GetAdapter(
    117         base::Bind(&BluetoothDetector::OnAdapterInitialized,
    118                    weak_ptr_factory_.GetWeakPtr()));
    119   }
    120 
    121   bool IsPresent() const { return adapter_.get() && adapter_->IsPresent(); }
    122 
    123   // device::BluetoothAdapter::Observer:
    124   virtual void AdapterPresentChanged(device::BluetoothAdapter* adapter,
    125                                      bool present) OVERRIDE {
    126     service_->OnBluetoothAdapterPresentChanged();
    127   }
    128 
    129  private:
    130   void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) {
    131     adapter_ = adapter;
    132     adapter_->AddObserver(this);
    133     service_->OnBluetoothAdapterPresentChanged();
    134   }
    135 
    136   // Owner of this class and should out-live this class.
    137   EasyUnlockService* service_;
    138   scoped_refptr<device::BluetoothAdapter> adapter_;
    139   base::WeakPtrFactory<BluetoothDetector> weak_ptr_factory_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(BluetoothDetector);
    142 };
    143 
    144 #if defined(OS_CHROMEOS)
    145 class EasyUnlockService::PowerMonitor
    146     : public chromeos::PowerManagerClient::Observer {
    147  public:
    148   explicit PowerMonitor(EasyUnlockService* service)
    149       : service_(service),
    150         waking_up_(false),
    151         weak_ptr_factory_(this) {
    152     chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
    153         AddObserver(this);
    154   }
    155 
    156   virtual ~PowerMonitor() {
    157     chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
    158         RemoveObserver(this);
    159   }
    160 
    161   bool waking_up() const { return waking_up_; }
    162 
    163  private:
    164   // chromeos::PowerManagerClient::Observer:
    165   virtual void SuspendImminent() OVERRIDE {
    166     service_->PrepareForSuspend();
    167   }
    168 
    169   virtual void SuspendDone(const base::TimeDelta& sleep_duration) OVERRIDE {
    170     waking_up_ = true;
    171     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
    172         FROM_HERE,
    173         base::Bind(&PowerMonitor::ResetWakingUp,
    174                    weak_ptr_factory_.GetWeakPtr()),
    175         base::TimeDelta::FromSeconds(5));
    176     service_->UpdateAppState();
    177     // Note that |this| may get deleted after |UpdateAppState| is called.
    178   }
    179 
    180   void ResetWakingUp() {
    181     waking_up_ = false;
    182     service_->UpdateAppState();
    183   }
    184 
    185   EasyUnlockService* service_;
    186   bool waking_up_;
    187   base::WeakPtrFactory<PowerMonitor> weak_ptr_factory_;
    188 
    189   DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
    190 };
    191 #endif
    192 
    193 EasyUnlockService::EasyUnlockService(Profile* profile)
    194     : profile_(profile),
    195       bluetooth_detector_(new BluetoothDetector(this)),
    196       shut_down_(false),
    197       weak_ptr_factory_(this) {
    198   extensions::ExtensionSystem::Get(profile_)->ready().Post(
    199       FROM_HERE,
    200       base::Bind(&EasyUnlockService::Initialize,
    201                  weak_ptr_factory_.GetWeakPtr()));
    202 }
    203 
    204 EasyUnlockService::~EasyUnlockService() {
    205 }
    206 
    207 // static
    208 void EasyUnlockService::RegisterProfilePrefs(
    209     user_prefs::PrefRegistrySyncable* registry) {
    210   registry->RegisterBooleanPref(
    211       prefs::kEasyUnlockEnabled,
    212       false,
    213       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    214   registry->RegisterDictionaryPref(
    215       prefs::kEasyUnlockPairing,
    216       new base::DictionaryValue(),
    217       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    218   registry->RegisterBooleanPref(
    219       prefs::kEasyUnlockAllowed,
    220       true,
    221       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
    222 }
    223 
    224 // static
    225 void EasyUnlockService::RegisterPrefs(PrefRegistrySimple* registry) {
    226   registry->RegisterDictionaryPref(prefs::kEasyUnlockHardlockState);
    227 }
    228 
    229 // static
    230 void EasyUnlockService::ResetLocalStateForUser(const std::string& user_id) {
    231   DCHECK(!user_id.empty());
    232 
    233   PrefService* local_state = GetLocalState();
    234   if (!local_state)
    235     return;
    236 
    237   DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
    238   update->RemoveWithoutPathExpansion(user_id, NULL);
    239 }
    240 
    241 bool EasyUnlockService::IsAllowed() {
    242   if (shut_down_)
    243     return false;
    244 
    245   if (!IsAllowedInternal())
    246     return false;
    247 
    248 #if defined(OS_CHROMEOS)
    249   if (!bluetooth_detector_->IsPresent())
    250     return false;
    251 
    252   return true;
    253 #else
    254   // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
    255   return false;
    256 #endif
    257 }
    258 
    259 void EasyUnlockService::SetHardlockState(
    260     EasyUnlockScreenlockStateHandler::HardlockState state) {
    261   const std::string user_id = GetUserEmail();
    262   if (user_id.empty())
    263     return;
    264 
    265   SetHardlockStateForUser(user_id, state);
    266 }
    267 
    268 EasyUnlockScreenlockStateHandler::HardlockState
    269 EasyUnlockService::GetHardlockState() const {
    270   EasyUnlockScreenlockStateHandler::HardlockState state;
    271   if (GetPersistedHardlockState(&state))
    272     return state;
    273 
    274   return EasyUnlockScreenlockStateHandler::NO_HARDLOCK;
    275 }
    276 
    277 bool EasyUnlockService::GetPersistedHardlockState(
    278     EasyUnlockScreenlockStateHandler::HardlockState* state) const {
    279   std::string user_id = GetUserEmail();
    280   if (user_id.empty())
    281     return false;
    282 
    283   PrefService* local_state = GetLocalState();
    284   if (!local_state)
    285     return false;
    286 
    287   const base::DictionaryValue* dict =
    288       local_state->GetDictionary(prefs::kEasyUnlockHardlockState);
    289   int state_int;
    290   if (dict && dict->GetIntegerWithoutPathExpansion(user_id, &state_int)) {
    291     *state =
    292         static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state_int);
    293     return true;
    294   }
    295 
    296   return false;
    297 }
    298 
    299 void EasyUnlockService::ShowInitialUserState() {
    300   if (!GetScreenlockStateHandler())
    301     return;
    302 
    303   EasyUnlockScreenlockStateHandler::HardlockState state;
    304   bool has_persisted_state = GetPersistedHardlockState(&state);
    305   if (!has_persisted_state)
    306     return;
    307 
    308   if (state == EasyUnlockScreenlockStateHandler::NO_HARDLOCK) {
    309     // Show connecting icon early when there is a persisted non hardlock state.
    310     UpdateScreenlockState(
    311         EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING);
    312   } else {
    313     screenlock_state_handler_->MaybeShowHardlockUI();
    314   }
    315 }
    316 
    317 EasyUnlockScreenlockStateHandler*
    318     EasyUnlockService::GetScreenlockStateHandler() {
    319   if (!IsAllowed())
    320     return NULL;
    321   if (!screenlock_state_handler_) {
    322     screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler(
    323         GetUserEmail(),
    324         GetHardlockState(),
    325         ScreenlockBridge::Get()));
    326   }
    327   return screenlock_state_handler_.get();
    328 }
    329 
    330 bool EasyUnlockService::UpdateScreenlockState(
    331     EasyUnlockScreenlockStateHandler::State state) {
    332   EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
    333   if (!handler)
    334     return false;
    335 
    336   handler->ChangeState(state);
    337 
    338   if (state != EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED)
    339     auth_attempt_.reset();
    340   return true;
    341 }
    342 
    343 void EasyUnlockService::AttemptAuth(const std::string& user_id) {
    344   auth_attempt_.reset(new EasyUnlockAuthAttempt(
    345       profile_,
    346       GetUserEmail(),
    347       GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK
    348                                 : EasyUnlockAuthAttempt::TYPE_SIGNIN));
    349   if (!auth_attempt_->Start(user_id))
    350     auth_attempt_.reset();
    351 }
    352 
    353 void EasyUnlockService::FinalizeUnlock(bool success) {
    354   if (auth_attempt_)
    355     auth_attempt_->FinalizeUnlock(GetUserEmail(), success);
    356   auth_attempt_.reset();
    357 }
    358 
    359 void EasyUnlockService::FinalizeSignin(const std::string& key) {
    360   if (!auth_attempt_)
    361     return;
    362   std::string wrapped_secret = GetWrappedSecret();
    363   if (!wrapped_secret.empty())
    364     auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key);
    365   auth_attempt_.reset();
    366 }
    367 
    368 void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() {
    369 #if defined(OS_CHROMEOS)
    370   std::string user_id = GetUserEmail();
    371   if (user_id.empty())
    372     return;
    373 
    374   const base::ListValue* device_list = GetRemoteDevices();
    375   std::set<std::string> paired_devices;
    376   if (device_list) {
    377     chromeos::EasyUnlockDeviceKeyDataList parsed_paired;
    378     chromeos::EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList(
    379         *device_list, &parsed_paired);
    380     for (const auto& device_key_data : parsed_paired)
    381       paired_devices.insert(device_key_data.psk);
    382   }
    383   if (paired_devices.empty()) {
    384     SetHardlockState(EasyUnlockScreenlockStateHandler::NO_PAIRING);
    385     return;
    386   }
    387 
    388   // No need to compare if a change is already recorded.
    389   if (GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_CHANGED ||
    390       GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_ADDED) {
    391     return;
    392   }
    393 
    394   chromeos::EasyUnlockKeyManager* key_manager =
    395       chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
    396   DCHECK(key_manager);
    397 
    398   key_manager->GetDeviceDataList(
    399       chromeos::UserContext(user_id),
    400       base::Bind(&EasyUnlockService::OnCryptohomeKeysFetchedForChecking,
    401                  weak_ptr_factory_.GetWeakPtr(),
    402                  user_id,
    403                  paired_devices));
    404 #endif
    405 }
    406 
    407 void EasyUnlockService::SetTrialRun() {
    408   DCHECK(GetType() == TYPE_REGULAR);
    409 
    410   EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
    411   if (handler)
    412     handler->SetTrialRun();
    413 }
    414 
    415 void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) {
    416   observers_.AddObserver(observer);
    417 }
    418 
    419 void EasyUnlockService::RemoveObserver(EasyUnlockServiceObserver* observer) {
    420   observers_.RemoveObserver(observer);
    421 }
    422 
    423 void  EasyUnlockService::Shutdown() {
    424   if (shut_down_)
    425     return;
    426   shut_down_ = true;
    427 
    428   ShutdownInternal();
    429 
    430   weak_ptr_factory_.InvalidateWeakPtrs();
    431 
    432   ResetScreenlockState();
    433   bluetooth_detector_.reset();
    434 #if defined(OS_CHROMEOS)
    435   power_monitor_.reset();
    436 #endif
    437 }
    438 
    439 void EasyUnlockService::LoadApp() {
    440   DCHECK(IsAllowed());
    441 
    442 #if defined(GOOGLE_CHROME_BUILD)
    443   base::FilePath easy_unlock_path;
    444 #if defined(OS_CHROMEOS)
    445   easy_unlock_path = base::FilePath("/usr/share/chromeos-assets/easy_unlock");
    446 #endif  // defined(OS_CHROMEOS)
    447 
    448 #ifndef NDEBUG
    449   // Only allow app path override switch for debug build.
    450   const CommandLine* command_line = CommandLine::ForCurrentProcess();
    451   if (command_line->HasSwitch(switches::kEasyUnlockAppPath)) {
    452     easy_unlock_path =
    453         command_line->GetSwitchValuePath(switches::kEasyUnlockAppPath);
    454   }
    455 #endif  // !defined(NDEBUG)
    456 
    457   if (!easy_unlock_path.empty()) {
    458     extensions::ComponentLoader* loader = GetComponentLoader(profile_);
    459     if (!loader->Exists(extension_misc::kEasyUnlockAppId))
    460       loader->Add(IDR_EASY_UNLOCK_MANIFEST, easy_unlock_path);
    461 
    462     ExtensionService* extension_service =
    463         extensions::ExtensionSystem::Get(profile_)->extension_service();
    464     extension_service->EnableExtension(extension_misc::kEasyUnlockAppId);
    465 
    466     NotifyUserUpdated();
    467   }
    468 #endif  // defined(GOOGLE_CHROME_BUILD)
    469 }
    470 
    471 void EasyUnlockService::DisableAppIfLoaded() {
    472   extensions::ComponentLoader* loader = GetComponentLoader(profile_);
    473   if (!loader->Exists(extension_misc::kEasyUnlockAppId))
    474     return;
    475 
    476   ExtensionService* extension_service =
    477       extensions::ExtensionSystem::Get(profile_)->extension_service();
    478   extension_service->DisableExtension(extension_misc::kEasyUnlockAppId,
    479                                       extensions::Extension::DISABLE_RELOAD);
    480 }
    481 
    482 void EasyUnlockService::UnloadApp() {
    483   GetComponentLoader(profile_)->Remove(extension_misc::kEasyUnlockAppId);
    484 }
    485 
    486 void EasyUnlockService::ReloadApp() {
    487   // Make sure lock screen state set by the extension gets reset.
    488   ResetScreenlockState();
    489 
    490   if (!GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId))
    491     return;
    492   extensions::ExtensionSystem* extension_system =
    493       extensions::ExtensionSystem::Get(profile_);
    494   extension_system->extension_service()->ReloadExtension(
    495       extension_misc::kEasyUnlockAppId);
    496   NotifyUserUpdated();
    497 }
    498 
    499 void EasyUnlockService::UpdateAppState() {
    500   if (IsAllowed()) {
    501     LoadApp();
    502 
    503 #if defined(OS_CHROMEOS)
    504     if (!power_monitor_)
    505       power_monitor_.reset(new PowerMonitor(this));
    506 #endif
    507   } else {
    508     bool bluetooth_waking_up = false;
    509 #if defined(OS_CHROMEOS)
    510     // If the service is not allowed due to bluetooth not being detected just
    511     // after system suspend is done, give bluetooth more time to be detected
    512     // before disabling the app (and resetting screenlock state).
    513     bluetooth_waking_up =
    514         power_monitor_.get() && power_monitor_->waking_up() &&
    515         !bluetooth_detector_->IsPresent();
    516 #endif
    517 
    518     if (!bluetooth_waking_up) {
    519       DisableAppIfLoaded();
    520       ResetScreenlockState();
    521 #if defined(OS_CHROMEOS)
    522       power_monitor_.reset();
    523 #endif
    524     }
    525   }
    526 }
    527 
    528 void EasyUnlockService::NotifyUserUpdated() {
    529   std::string user_id = GetUserEmail();
    530   if (user_id.empty())
    531     return;
    532 
    533   // Notify the easy unlock app that the user info changed.
    534   extensions::api::easy_unlock_private::UserInfo info;
    535   info.user_id = user_id;
    536   info.logged_in = GetType() == TYPE_REGULAR;
    537   info.data_ready = info.logged_in || GetRemoteDevices() != NULL;
    538 
    539   scoped_ptr<base::ListValue> args(new base::ListValue());
    540   args->Append(info.ToValue().release());
    541 
    542   scoped_ptr<extensions::Event> event(new extensions::Event(
    543       extensions::api::easy_unlock_private::OnUserInfoUpdated::kEventName,
    544       args.Pass()));
    545 
    546   extensions::EventRouter::Get(profile_)->DispatchEventToExtension(
    547        extension_misc::kEasyUnlockAppId, event.Pass());
    548 }
    549 
    550 void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
    551   FOR_EACH_OBSERVER(
    552       EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged());
    553 }
    554 
    555 void EasyUnlockService::ResetScreenlockState() {
    556   screenlock_state_handler_.reset();
    557   auth_attempt_.reset();
    558 }
    559 
    560 void EasyUnlockService::SetScreenlockHardlockedState(
    561     EasyUnlockScreenlockStateHandler::HardlockState state) {
    562   if (screenlock_state_handler_)
    563     screenlock_state_handler_->SetHardlockState(state);
    564   if (state != EasyUnlockScreenlockStateHandler::NO_HARDLOCK)
    565     auth_attempt_.reset();
    566 }
    567 
    568 void EasyUnlockService::Initialize() {
    569   InitializeInternal();
    570 
    571 #if defined(OS_CHROMEOS)
    572   // Only start Bluetooth detection for ChromeOS since the feature is
    573   // only offered on ChromeOS. Enabling this on non-ChromeOS platforms
    574   // previously introduced a performance regression: http://crbug.com/404482
    575   // Make sure not to reintroduce a performance regression if re-enabling on
    576   // additional platforms.
    577   // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
    578   bluetooth_detector_->Initialize();
    579 #endif  // defined(OS_CHROMEOS)
    580 }
    581 
    582 void EasyUnlockService::OnBluetoothAdapterPresentChanged() {
    583   UpdateAppState();
    584 }
    585 
    586 void EasyUnlockService::SetHardlockStateForUser(
    587       const std::string& user_id,
    588       EasyUnlockScreenlockStateHandler::HardlockState state) {
    589   DCHECK(!user_id.empty());
    590 
    591   PrefService* local_state = GetLocalState();
    592   if (!local_state)
    593     return;
    594 
    595   DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
    596   update->SetIntegerWithoutPathExpansion(user_id, static_cast<int>(state));
    597 
    598   if (GetUserEmail() == user_id)
    599     SetScreenlockHardlockedState(state);
    600 }
    601 
    602 #if defined(OS_CHROMEOS)
    603 void EasyUnlockService::OnCryptohomeKeysFetchedForChecking(
    604     const std::string& user_id,
    605     const std::set<std::string> paired_devices,
    606     bool success,
    607     const chromeos::EasyUnlockDeviceKeyDataList& key_data_list) {
    608   DCHECK(!user_id.empty() && !paired_devices.empty());
    609 
    610   if (!success) {
    611     SetHardlockStateForUser(user_id,
    612                             EasyUnlockScreenlockStateHandler::NO_PAIRING);
    613     return;
    614   }
    615 
    616   std::set<std::string> devices_in_cryptohome;
    617   for (const auto& device_key_data : key_data_list)
    618     devices_in_cryptohome.insert(device_key_data.psk);
    619 
    620   if (paired_devices != devices_in_cryptohome ||
    621       GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) {
    622     SetHardlockStateForUser(
    623         user_id,
    624         devices_in_cryptohome.empty()
    625             ? EasyUnlockScreenlockStateHandler::PAIRING_ADDED
    626             : EasyUnlockScreenlockStateHandler::PAIRING_CHANGED);
    627   }
    628 }
    629 #endif
    630 
    631 void EasyUnlockService::PrepareForSuspend() {
    632   DisableAppIfLoaded();
    633   if (screenlock_state_handler_ && screenlock_state_handler_->IsActive()) {
    634     UpdateScreenlockState(
    635         EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING);
    636   }
    637 }
    638 
    639