Standardize usage of virtual/override/final in chrome/browser/signin/
[chromium-blink-merge.git] / chrome / browser / signin / easy_unlock_service.cc
blobecfe4dd375fee56bde0a2dc9680ac277560e360a
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 "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"
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
48 namespace {
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();
58 PrefService* GetLocalState() {
59 return g_browser_process ? g_browser_process->local_state() : NULL;
62 } // namespace
64 // static
65 EasyUnlockService* EasyUnlockService::Get(Profile* profile) {
66 return EasyUnlockServiceFactory::GetForProfile(profile);
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
82 // static
83 bool EasyUnlockService::IsSignInEnabled() {
84 #if defined(OS_CHROMEOS)
85 const std::string group_name =
86 base::FieldTrialList::FindFullName("EasySignIn");
88 if (CommandLine::ForCurrentProcess()->HasSwitch(
89 chromeos::switches::kDisableEasySignin)) {
90 return false;
93 return group_name == "Enable";
94 #else
95 return false;
96 #endif
99 class EasyUnlockService::BluetoothDetector
100 : public device::BluetoothAdapter::Observer {
101 public:
102 explicit BluetoothDetector(EasyUnlockService* service)
103 : service_(service),
104 weak_ptr_factory_(this) {
107 ~BluetoothDetector() override {
108 if (adapter_.get())
109 adapter_->RemoveObserver(this);
112 void Initialize() {
113 if (!device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable())
114 return;
116 device::BluetoothAdapterFactory::GetAdapter(
117 base::Bind(&BluetoothDetector::OnAdapterInitialized,
118 weak_ptr_factory_.GetWeakPtr()));
121 bool IsPresent() const { return adapter_.get() && adapter_->IsPresent(); }
123 // device::BluetoothAdapter::Observer:
124 void AdapterPresentChanged(device::BluetoothAdapter* adapter,
125 bool present) override {
126 service_->OnBluetoothAdapterPresentChanged();
129 private:
130 void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) {
131 adapter_ = adapter;
132 adapter_->AddObserver(this);
133 service_->OnBluetoothAdapterPresentChanged();
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_;
141 DISALLOW_COPY_AND_ASSIGN(BluetoothDetector);
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);
156 virtual ~PowerMonitor() {
157 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
158 RemoveObserver(this);
161 bool waking_up() const { return waking_up_; }
163 private:
164 // chromeos::PowerManagerClient::Observer:
165 virtual void SuspendImminent() override {
166 service_->PrepareForSuspend();
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.
180 void ResetWakingUp() {
181 waking_up_ = false;
182 service_->UpdateAppState();
185 EasyUnlockService* service_;
186 bool waking_up_;
187 base::WeakPtrFactory<PowerMonitor> weak_ptr_factory_;
189 DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
191 #endif
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()));
204 EasyUnlockService::~EasyUnlockService() {
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);
224 // static
225 void EasyUnlockService::RegisterPrefs(PrefRegistrySimple* registry) {
226 registry->RegisterDictionaryPref(prefs::kEasyUnlockHardlockState);
229 // static
230 void EasyUnlockService::ResetLocalStateForUser(const std::string& user_id) {
231 DCHECK(!user_id.empty());
233 PrefService* local_state = GetLocalState();
234 if (!local_state)
235 return;
237 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
238 update->RemoveWithoutPathExpansion(user_id, NULL);
241 bool EasyUnlockService::IsAllowed() {
242 if (shut_down_)
243 return false;
245 if (!IsAllowedInternal())
246 return false;
248 #if defined(OS_CHROMEOS)
249 if (!bluetooth_detector_->IsPresent())
250 return false;
252 return true;
253 #else
254 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
255 return false;
256 #endif
259 void EasyUnlockService::SetHardlockState(
260 EasyUnlockScreenlockStateHandler::HardlockState state) {
261 const std::string user_id = GetUserEmail();
262 if (user_id.empty())
263 return;
265 SetHardlockStateForUser(user_id, state);
268 EasyUnlockScreenlockStateHandler::HardlockState
269 EasyUnlockService::GetHardlockState() const {
270 std::string user_id = GetUserEmail();
271 if (user_id.empty())
272 return EasyUnlockScreenlockStateHandler::NO_HARDLOCK;
274 PrefService* local_state = GetLocalState();
275 if (!local_state)
276 return EasyUnlockScreenlockStateHandler::NO_HARDLOCK;
278 const base::DictionaryValue* dict =
279 local_state->GetDictionary(prefs::kEasyUnlockHardlockState);
280 int state;
281 if (!dict || !dict->GetIntegerWithoutPathExpansion(user_id, &state))
282 return EasyUnlockScreenlockStateHandler::NO_HARDLOCK;
284 return static_cast<EasyUnlockScreenlockStateHandler::HardlockState>(state);
287 void EasyUnlockService::MaybeShowHardlockUI() {
288 if (GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_HARDLOCK)
289 return;
290 if (GetScreenlockStateHandler())
291 screenlock_state_handler_->MaybeShowHardlockUI();
294 EasyUnlockScreenlockStateHandler*
295 EasyUnlockService::GetScreenlockStateHandler() {
296 if (!IsAllowed())
297 return NULL;
298 if (!screenlock_state_handler_) {
299 screenlock_state_handler_.reset(new EasyUnlockScreenlockStateHandler(
300 GetUserEmail(),
301 GetHardlockState(),
302 ScreenlockBridge::Get()));
304 return screenlock_state_handler_.get();
307 bool EasyUnlockService::UpdateScreenlockState(
308 EasyUnlockScreenlockStateHandler::State state) {
309 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
310 if (!handler)
311 return false;
313 handler->ChangeState(state);
315 if (state != EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED)
316 auth_attempt_.reset();
317 return true;
320 void EasyUnlockService::AttemptAuth(const std::string& user_id) {
321 auth_attempt_.reset(new EasyUnlockAuthAttempt(
322 profile_,
323 GetUserEmail(),
324 GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK
325 : EasyUnlockAuthAttempt::TYPE_SIGNIN));
326 if (!auth_attempt_->Start(user_id))
327 auth_attempt_.reset();
330 void EasyUnlockService::FinalizeUnlock(bool success) {
331 if (auth_attempt_)
332 auth_attempt_->FinalizeUnlock(GetUserEmail(), success);
333 auth_attempt_.reset();
336 void EasyUnlockService::FinalizeSignin(const std::string& key) {
337 if (!auth_attempt_)
338 return;
339 std::string wrapped_secret = GetWrappedSecret();
340 if (!wrapped_secret.empty())
341 auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key);
342 auth_attempt_.reset();
345 void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() {
346 #if defined(OS_CHROMEOS)
347 std::string user_id = GetUserEmail();
348 if (user_id.empty())
349 return;
351 const base::ListValue* device_list = GetRemoteDevices();
352 std::set<std::string> paired_devices;
353 if (device_list) {
354 chromeos::EasyUnlockDeviceKeyDataList parsed_paired;
355 chromeos::EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList(
356 *device_list, &parsed_paired);
357 for (const auto& device_key_data : parsed_paired)
358 paired_devices.insert(device_key_data.public_key);
360 if (paired_devices.empty()) {
361 SetHardlockState(EasyUnlockScreenlockStateHandler::NO_PAIRING);
362 return;
365 // No need to compare if a change is already recorded.
366 if (GetHardlockState() == EasyUnlockScreenlockStateHandler::PAIRING_CHANGED)
367 return;
369 chromeos::EasyUnlockKeyManager* key_manager =
370 chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager();
371 DCHECK(key_manager);
373 key_manager->GetDeviceDataList(
374 chromeos::UserContext(user_id),
375 base::Bind(&EasyUnlockService::OnCryptohomeKeysFetchedForChecking,
376 weak_ptr_factory_.GetWeakPtr(),
377 user_id,
378 paired_devices));
379 #endif
382 void EasyUnlockService::SetTrialRun() {
383 DCHECK(GetType() == TYPE_REGULAR);
385 EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
386 if (handler)
387 handler->SetTrialRun();
390 void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) {
391 observers_.AddObserver(observer);
394 void EasyUnlockService::RemoveObserver(EasyUnlockServiceObserver* observer) {
395 observers_.RemoveObserver(observer);
398 void EasyUnlockService::Shutdown() {
399 if (shut_down_)
400 return;
401 shut_down_ = true;
403 ShutdownInternal();
405 weak_ptr_factory_.InvalidateWeakPtrs();
407 ResetScreenlockState();
408 bluetooth_detector_.reset();
409 #if defined(OS_CHROMEOS)
410 power_monitor_.reset();
411 #endif
414 void EasyUnlockService::LoadApp() {
415 DCHECK(IsAllowed());
417 #if defined(GOOGLE_CHROME_BUILD)
418 base::FilePath easy_unlock_path;
419 #if defined(OS_CHROMEOS)
420 easy_unlock_path = base::FilePath("/usr/share/chromeos-assets/easy_unlock");
421 #endif // defined(OS_CHROMEOS)
423 #ifndef NDEBUG
424 // Only allow app path override switch for debug build.
425 const CommandLine* command_line = CommandLine::ForCurrentProcess();
426 if (command_line->HasSwitch(switches::kEasyUnlockAppPath)) {
427 easy_unlock_path =
428 command_line->GetSwitchValuePath(switches::kEasyUnlockAppPath);
430 #endif // !defined(NDEBUG)
432 if (!easy_unlock_path.empty()) {
433 extensions::ComponentLoader* loader = GetComponentLoader(profile_);
434 if (!loader->Exists(extension_misc::kEasyUnlockAppId))
435 loader->Add(IDR_EASY_UNLOCK_MANIFEST, easy_unlock_path);
437 ExtensionService* extension_service =
438 extensions::ExtensionSystem::Get(profile_)->extension_service();
439 extension_service->EnableExtension(extension_misc::kEasyUnlockAppId);
441 NotifyUserUpdated();
443 #endif // defined(GOOGLE_CHROME_BUILD)
446 void EasyUnlockService::DisableAppIfLoaded() {
447 extensions::ComponentLoader* loader = GetComponentLoader(profile_);
448 if (!loader->Exists(extension_misc::kEasyUnlockAppId))
449 return;
451 ExtensionService* extension_service =
452 extensions::ExtensionSystem::Get(profile_)->extension_service();
453 extension_service->DisableExtension(extension_misc::kEasyUnlockAppId,
454 extensions::Extension::DISABLE_RELOAD);
457 void EasyUnlockService::UnloadApp() {
458 GetComponentLoader(profile_)->Remove(extension_misc::kEasyUnlockAppId);
461 void EasyUnlockService::ReloadApp() {
462 // Make sure lock screen state set by the extension gets reset.
463 ResetScreenlockState();
465 if (!GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId))
466 return;
467 extensions::ExtensionSystem* extension_system =
468 extensions::ExtensionSystem::Get(profile_);
469 extension_system->extension_service()->ReloadExtension(
470 extension_misc::kEasyUnlockAppId);
471 NotifyUserUpdated();
474 void EasyUnlockService::UpdateAppState() {
475 if (IsAllowed()) {
476 LoadApp();
478 #if defined(OS_CHROMEOS)
479 if (!power_monitor_)
480 power_monitor_.reset(new PowerMonitor(this));
481 #endif
482 } else {
483 bool bluetooth_waking_up = false;
484 #if defined(OS_CHROMEOS)
485 // If the service is not allowed due to bluetooth not being detected just
486 // after system suspend is done, give bluetooth more time to be detected
487 // before disabling the app (and resetting screenlock state).
488 bluetooth_waking_up =
489 power_monitor_.get() && power_monitor_->waking_up() &&
490 !bluetooth_detector_->IsPresent();
491 #endif
493 if (!bluetooth_waking_up) {
494 DisableAppIfLoaded();
495 ResetScreenlockState();
496 #if defined(OS_CHROMEOS)
497 power_monitor_.reset();
498 #endif
503 void EasyUnlockService::NotifyUserUpdated() {
504 std::string user_id = GetUserEmail();
505 if (user_id.empty())
506 return;
508 // Notify the easy unlock app that the user info changed.
509 extensions::api::easy_unlock_private::UserInfo info;
510 info.user_id = user_id;
511 info.logged_in = GetType() == TYPE_REGULAR;
512 info.data_ready = info.logged_in || GetRemoteDevices() != NULL;
514 scoped_ptr<base::ListValue> args(new base::ListValue());
515 args->Append(info.ToValue().release());
517 scoped_ptr<extensions::Event> event(new extensions::Event(
518 extensions::api::easy_unlock_private::OnUserInfoUpdated::kEventName,
519 args.Pass()));
521 extensions::EventRouter::Get(profile_)->DispatchEventToExtension(
522 extension_misc::kEasyUnlockAppId, event.Pass());
525 void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
526 FOR_EACH_OBSERVER(
527 EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged());
530 void EasyUnlockService::ResetScreenlockState() {
531 screenlock_state_handler_.reset();
532 auth_attempt_.reset();
535 void EasyUnlockService::SetScreenlockHardlockedState(
536 EasyUnlockScreenlockStateHandler::HardlockState state) {
537 if (screenlock_state_handler_)
538 screenlock_state_handler_->SetHardlockState(state);
539 if (state != EasyUnlockScreenlockStateHandler::NO_HARDLOCK)
540 auth_attempt_.reset();
543 void EasyUnlockService::Initialize() {
544 InitializeInternal();
546 #if defined(OS_CHROMEOS)
547 // Only start Bluetooth detection for ChromeOS since the feature is
548 // only offered on ChromeOS. Enabling this on non-ChromeOS platforms
549 // previously introduced a performance regression: http://crbug.com/404482
550 // Make sure not to reintroduce a performance regression if re-enabling on
551 // additional platforms.
552 // TODO(xiyuan): Revisit when non-chromeos platforms are supported.
553 bluetooth_detector_->Initialize();
554 #endif // defined(OS_CHROMEOS)
557 void EasyUnlockService::OnBluetoothAdapterPresentChanged() {
558 UpdateAppState();
561 void EasyUnlockService::SetHardlockStateForUser(
562 const std::string& user_id,
563 EasyUnlockScreenlockStateHandler::HardlockState state) {
564 DCHECK(!user_id.empty());
566 PrefService* local_state = GetLocalState();
567 if (!local_state)
568 return;
570 DictionaryPrefUpdate update(local_state, prefs::kEasyUnlockHardlockState);
571 update->SetIntegerWithoutPathExpansion(user_id, static_cast<int>(state));
573 if (GetUserEmail() == user_id)
574 SetScreenlockHardlockedState(state);
577 #if defined(OS_CHROMEOS)
578 void EasyUnlockService::OnCryptohomeKeysFetchedForChecking(
579 const std::string& user_id,
580 const std::set<std::string> paired_devices,
581 bool success,
582 const chromeos::EasyUnlockDeviceKeyDataList& key_data_list) {
583 DCHECK(!user_id.empty() && !paired_devices.empty());
585 if (!success) {
586 SetHardlockStateForUser(user_id,
587 EasyUnlockScreenlockStateHandler::NO_PAIRING);
588 return;
591 std::set<std::string> devices_in_cryptohome;
592 for (const auto& device_key_data : key_data_list)
593 devices_in_cryptohome.insert(device_key_data.public_key);
595 if (paired_devices != devices_in_cryptohome ||
596 GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) {
597 SetHardlockStateForUser(user_id,
598 EasyUnlockScreenlockStateHandler::PAIRING_CHANGED);
601 #endif
603 void EasyUnlockService::PrepareForSuspend() {
604 DisableAppIfLoaded();
605 if (screenlock_state_handler_ && screenlock_state_handler_->IsActive()) {
606 UpdateScreenlockState(
607 EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING);