12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031 |
- // Copyright 2015 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/components/proximity_auth/unlock_manager_impl.h"
- #include <memory>
- #include "ash/components/multidevice/logging/logging.h"
- #include "ash/components/multidevice/remote_device_ref.h"
- #include "ash/components/proximity_auth/messenger.h"
- #include "ash/components/proximity_auth/metrics.h"
- #include "ash/components/proximity_auth/proximity_auth_client.h"
- #include "ash/components/proximity_auth/proximity_monitor_impl.h"
- #include "ash/services/secure_channel/public/cpp/client/client_channel.h"
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/default_clock.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "device/bluetooth/bluetooth_adapter_factory.h"
- namespace proximity_auth {
- namespace {
- using SmartLockState = ash::SmartLockState;
- // This enum is tied directly to a UMA enum defined in
- // //tools/metrics/histograms/enums.xml, and should always reflect it (do not
- // change one without changing the other). Entries should be never modified
- // or deleted. Only additions possible.
- enum class FindAndConnectToHostResult {
- kFoundAndConnectedToHost = 0,
- kCanceledBluetoothDisabled = 1,
- kCanceledUserEnteredPassword = 2,
- kSecureChannelConnectionAttemptFailure = 3,
- kTimedOut = 4,
- kMaxValue = kTimedOut
- };
- // The maximum amount of time that the unlock manager can stay in the 'waking
- // up' state after resuming from sleep.
- constexpr base::TimeDelta kWakingUpDuration = base::Seconds(15);
- // The maximum amount of time that we wait for the BluetoothAdapter to be
- // fully initialized after resuming from sleep.
- // TODO(crbug.com/986896): This is necessary because the BluetoothAdapter
- // returns incorrect presence and power values directly after resume, and does
- // not return correct values until about 1-2 seconds later. Remove this once
- // the bug is fixed.
- constexpr base::TimeDelta kBluetoothAdapterResumeMaxDuration = base::Seconds(3);
- // The limit on the elapsed time for an auth attempt. If an auth attempt exceeds
- // this limit, it will time out and be rejected. This is provided as a failsafe,
- // in case something goes wrong.
- constexpr base::TimeDelta kAuthAttemptTimeout = base::Seconds(5);
- constexpr base::TimeDelta kMinExtendedDuration = base::Milliseconds(1);
- constexpr base::TimeDelta kMaxExtendedDuration = base::Seconds(15);
- const int kNumDurationMetricBuckets = 100;
- const char kGetRemoteStatusNone[] = "none";
- const char kGetRemoteStatusSuccess[] = "success";
- // The subset of SmartLockStates that represent the first non-trival status
- // shown to the user. Entries persisted to UMA histograms; do not reorder or
- // delete enum values.
- enum class FirstSmartLockStatus {
- kBluetoothDisabled = 0,
- kPhoneNotLockable = 1,
- kPhoneNotFound = 2,
- kPhoneNotAuthenticated = 3,
- kPhoneFoundLockedAndDistant = 4,
- kPhoneFoundLockedAndProximate = 5,
- kPhoneFoundUnlockedAndDistant = 6,
- kPhoneAuthenticated = 7,
- kPrimaryUserAbsent = 8,
- kMaxValue = kPrimaryUserAbsent
- };
- absl::optional<FirstSmartLockStatus> GetFirstSmartLockStatus(
- SmartLockState state) {
- switch (state) {
- case SmartLockState::kBluetoothDisabled:
- return FirstSmartLockStatus::kBluetoothDisabled;
- case SmartLockState::kPhoneNotLockable:
- return FirstSmartLockStatus::kPhoneNotLockable;
- case SmartLockState::kPhoneNotFound:
- return FirstSmartLockStatus::kPhoneNotFound;
- case SmartLockState::kPhoneNotAuthenticated:
- return FirstSmartLockStatus::kPhoneNotAuthenticated;
- case SmartLockState::kPhoneFoundLockedAndDistant:
- return FirstSmartLockStatus::kPhoneFoundLockedAndDistant;
- case SmartLockState::kPhoneFoundLockedAndProximate:
- return FirstSmartLockStatus::kPhoneFoundLockedAndProximate;
- case SmartLockState::kPhoneFoundUnlockedAndDistant:
- return FirstSmartLockStatus::kPhoneFoundUnlockedAndDistant;
- case SmartLockState::kPhoneAuthenticated:
- return FirstSmartLockStatus::kPhoneAuthenticated;
- case SmartLockState::kPrimaryUserAbsent:
- return FirstSmartLockStatus::kPrimaryUserAbsent;
- default:
- return absl::nullopt;
- }
- }
- // Returns the remote device's security settings state, for metrics,
- // corresponding to a remote status update.
- metrics::RemoteSecuritySettingsState GetRemoteSecuritySettingsState(
- const RemoteStatusUpdate& status_update) {
- switch (status_update.secure_screen_lock_state) {
- case SECURE_SCREEN_LOCK_STATE_UNKNOWN:
- return metrics::RemoteSecuritySettingsState::UNKNOWN;
- case SECURE_SCREEN_LOCK_DISABLED:
- switch (status_update.trust_agent_state) {
- case TRUST_AGENT_UNSUPPORTED:
- return metrics::RemoteSecuritySettingsState::
- SCREEN_LOCK_DISABLED_TRUST_AGENT_UNSUPPORTED;
- case TRUST_AGENT_DISABLED:
- return metrics::RemoteSecuritySettingsState::
- SCREEN_LOCK_DISABLED_TRUST_AGENT_DISABLED;
- case TRUST_AGENT_ENABLED:
- return metrics::RemoteSecuritySettingsState::
- SCREEN_LOCK_DISABLED_TRUST_AGENT_ENABLED;
- }
- case SECURE_SCREEN_LOCK_ENABLED:
- switch (status_update.trust_agent_state) {
- case TRUST_AGENT_UNSUPPORTED:
- return metrics::RemoteSecuritySettingsState::
- SCREEN_LOCK_ENABLED_TRUST_AGENT_UNSUPPORTED;
- case TRUST_AGENT_DISABLED:
- return metrics::RemoteSecuritySettingsState::
- SCREEN_LOCK_ENABLED_TRUST_AGENT_DISABLED;
- case TRUST_AGENT_ENABLED:
- return metrics::RemoteSecuritySettingsState::
- SCREEN_LOCK_ENABLED_TRUST_AGENT_ENABLED;
- }
- }
- NOTREACHED();
- return metrics::RemoteSecuritySettingsState::UNKNOWN;
- }
- std::string GetHistogramStatusSuffix(bool unlockable) {
- return unlockable ? "Unlockable" : "Other";
- }
- std::string GetHistogramScreenLockTypeName(
- ProximityAuthSystem::ScreenlockType screenlock_type) {
- return screenlock_type == ProximityAuthSystem::SESSION_LOCK ? "Unlock"
- : "SignIn";
- }
- void RecordFindAndConnectToHostResult(
- ProximityAuthSystem::ScreenlockType screenlock_type,
- FindAndConnectToHostResult result) {
- base::UmaHistogramEnumeration(
- "SmartLock.FindAndConnectToHostResult." +
- GetHistogramScreenLockTypeName(screenlock_type),
- result);
- }
- void RecordAuthResultFailure(
- ProximityAuthSystem::ScreenlockType screenlock_type,
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason failure_reason) {
- if (screenlock_type == ProximityAuthSystem::SESSION_LOCK) {
- SmartLockMetricsRecorder::RecordAuthResultUnlockFailure(failure_reason);
- } else if (screenlock_type == ProximityAuthSystem::SIGN_IN) {
- SmartLockMetricsRecorder::RecordAuthResultSignInFailure(failure_reason);
- }
- }
- void RecordExtendedDurationTimerMetric(const std::string& histogram_name,
- base::TimeDelta duration) {
- // Use a custom |max| to account for Smart Lock's timeout (larger than the
- // default 10 seconds).
- base::UmaHistogramCustomTimes(
- histogram_name, duration, kMinExtendedDuration /* min */,
- kMaxExtendedDuration /* max */, kNumDurationMetricBuckets /* buckets */);
- }
- bool HasCommunicatedWithPhone(SmartLockState state) {
- switch (state) {
- case SmartLockState::kDisabled:
- [[fallthrough]];
- case SmartLockState::kInactive:
- [[fallthrough]];
- case SmartLockState::kBluetoothDisabled:
- [[fallthrough]];
- case SmartLockState::kPhoneNotFound:
- [[fallthrough]];
- case SmartLockState::kConnectingToPhone:
- [[fallthrough]];
- case SmartLockState::kPasswordReentryRequired:
- return false;
- case SmartLockState::kPhoneNotLockable:
- [[fallthrough]];
- case SmartLockState::kPhoneNotAuthenticated:
- [[fallthrough]];
- case SmartLockState::kPhoneFoundLockedAndDistant:
- [[fallthrough]];
- case SmartLockState::kPhoneFoundLockedAndProximate:
- [[fallthrough]];
- case SmartLockState::kPhoneFoundUnlockedAndDistant:
- [[fallthrough]];
- case SmartLockState::kPhoneAuthenticated:
- [[fallthrough]];
- case SmartLockState::kPrimaryUserAbsent:
- return true;
- }
- }
- } // namespace
- UnlockManagerImpl::UnlockManagerImpl(
- ProximityAuthSystem::ScreenlockType screenlock_type,
- ProximityAuthClient* proximity_auth_client)
- : screenlock_type_(screenlock_type),
- proximity_auth_client_(proximity_auth_client),
- bluetooth_suspension_recovery_timer_(
- std::make_unique<base::OneShotTimer>()) {
- chromeos::PowerManagerClient::Get()->AddObserver(this);
- if (device::BluetoothAdapterFactory::IsBluetoothSupported()) {
- device::BluetoothAdapterFactory::Get()->GetAdapter(
- base::BindOnce(&UnlockManagerImpl::OnBluetoothAdapterInitialized,
- weak_ptr_factory_.GetWeakPtr()));
- }
- }
- UnlockManagerImpl::~UnlockManagerImpl() {
- if (life_cycle_)
- life_cycle_->RemoveObserver(this);
- if (GetMessenger())
- GetMessenger()->RemoveObserver(this);
- if (proximity_monitor_)
- proximity_monitor_->RemoveObserver(this);
- chromeos::PowerManagerClient::Get()->RemoveObserver(this);
- if (bluetooth_adapter_)
- bluetooth_adapter_->RemoveObserver(this);
- }
- bool UnlockManagerImpl::IsUnlockAllowed() {
- return (remote_screenlock_state_ &&
- *remote_screenlock_state_ == RemoteScreenlockState::UNLOCKED &&
- is_bluetooth_connection_to_phone_active_ && proximity_monitor_ &&
- proximity_monitor_->IsUnlockAllowed() &&
- (screenlock_type_ != ProximityAuthSystem::SIGN_IN || GetMessenger()));
- }
- void UnlockManagerImpl::SetRemoteDeviceLifeCycle(
- RemoteDeviceLifeCycle* life_cycle) {
- PA_LOG(VERBOSE) << "Request received to change scan state to: "
- << (life_cycle == nullptr ? "inactive" : "active") << ".";
- if (life_cycle_)
- life_cycle_->RemoveObserver(this);
- if (GetMessenger())
- GetMessenger()->RemoveObserver(this);
- life_cycle_ = life_cycle;
- if (life_cycle_) {
- life_cycle_->AddObserver(this);
- is_bluetooth_connection_to_phone_active_ = false;
- show_lock_screen_time_ = base::DefaultClock::GetInstance()->Now();
- has_user_been_shown_first_status_ = false;
- if (IsBluetoothPresentAndPowered()) {
- SetIsPerformingInitialScan(true /* is_performing_initial_scan */);
- AttemptToStartRemoteDeviceLifecycle();
- } else {
- RecordFindAndConnectToHostResult(
- screenlock_type_,
- FindAndConnectToHostResult::kCanceledBluetoothDisabled);
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- }
- } else {
- ResetPerformanceMetricsTimestamps();
- if (proximity_monitor_)
- proximity_monitor_->RemoveObserver(this);
- proximity_monitor_.reset();
- UpdateLockScreen();
- }
- }
- void UnlockManagerImpl::OnLifeCycleStateChanged(
- RemoteDeviceLifeCycle::State old_state,
- RemoteDeviceLifeCycle::State new_state) {
- remote_screenlock_state_.reset();
- if (new_state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) {
- DCHECK(life_cycle_->GetChannel());
- DCHECK(GetMessenger());
- if (!proximity_monitor_) {
- proximity_monitor_ = CreateProximityMonitor(life_cycle_);
- proximity_monitor_->AddObserver(this);
- proximity_monitor_->Start();
- }
- GetMessenger()->AddObserver(this);
- is_bluetooth_connection_to_phone_active_ = true;
- attempt_get_remote_status_start_time_ =
- base::DefaultClock::GetInstance()->Now();
- PA_LOG(VERBOSE) << "Successfully connected to host; waiting for remote "
- "status update.";
- if (is_performing_initial_scan_) {
- RecordFindAndConnectToHostResult(
- screenlock_type_,
- FindAndConnectToHostResult::kFoundAndConnectedToHost);
- }
- } else {
- is_bluetooth_connection_to_phone_active_ = false;
- if (proximity_monitor_) {
- proximity_monitor_->RemoveObserver(this);
- proximity_monitor_->Stop();
- proximity_monitor_.reset();
- }
- }
- // Note: though the name is AUTHENTICATION_FAILED, this state actually
- // encompasses any connection failure in
- // `ash::secure_channel::mojom::ConnectionAttemptFailureReason` beside
- // Bluetooth becoming disabled. See https://crbug.com/991644 for more.
- if (new_state == RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED) {
- PA_LOG(ERROR) << "Connection attempt to host failed.";
- if (is_performing_initial_scan_) {
- RecordFindAndConnectToHostResult(
- screenlock_type_,
- FindAndConnectToHostResult::kSecureChannelConnectionAttemptFailure);
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- }
- }
- if (new_state == RemoteDeviceLifeCycle::State::FINDING_CONNECTION &&
- old_state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) {
- PA_LOG(ERROR) << "Secure channel dropped for unknown reason; potentially "
- "due to Bluetooth being disabled.";
- if (is_performing_initial_scan_) {
- OnDisconnected();
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- }
- }
- UpdateLockScreen();
- }
- void UnlockManagerImpl::OnUnlockEventSent(bool success) {
- if (!is_attempting_auth_) {
- PA_LOG(ERROR) << "Sent easy_unlock event, but no auth attempted.";
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kUnlockEventSentButNotAttemptingAuth);
- } else if (success) {
- FinalizeAuthAttempt(absl::nullopt /* failure_reason */);
- } else {
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kFailedtoNotifyHostDeviceThatSmartLockWasUsed);
- }
- }
- void UnlockManagerImpl::OnRemoteStatusUpdate(
- const RemoteStatusUpdate& status_update) {
- PA_LOG(VERBOSE) << "Status Update: ("
- << "user_present=" << status_update.user_presence << ", "
- << "secure_screen_lock="
- << status_update.secure_screen_lock_state << ", "
- << "trust_agent=" << status_update.trust_agent_state << ")";
- metrics::RecordRemoteSecuritySettingsState(
- GetRemoteSecuritySettingsState(status_update));
- remote_screenlock_state_ = std::make_unique<RemoteScreenlockState>(
- GetScreenlockStateFromRemoteUpdate(status_update));
- // Only record these metrics within the initial period of opening the laptop
- // displaying the lock screen.
- if (is_performing_initial_scan_) {
- RecordFirstRemoteStatusReceived(
- *remote_screenlock_state_ ==
- RemoteScreenlockState::UNLOCKED /* unlockable */);
- }
- // This also calls |UpdateLockScreen()|
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- }
- void UnlockManagerImpl::OnDecryptResponse(const std::string& decrypted_bytes) {
- if (!is_attempting_auth_) {
- PA_LOG(ERROR) << "Decrypt response received but not attempting auth.";
- return;
- }
- if (decrypted_bytes.empty()) {
- PA_LOG(WARNING) << "Failed to decrypt sign-in challenge.";
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kFailedToDecryptSignInChallenge);
- } else {
- sign_in_secret_ = std::make_unique<std::string>(decrypted_bytes);
- if (GetMessenger())
- GetMessenger()->DispatchUnlockEvent();
- }
- }
- void UnlockManagerImpl::OnUnlockResponse(bool success) {
- if (!is_attempting_auth_) {
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kUnlockRequestSentButNotAttemptingAuth);
- PA_LOG(ERROR) << "Unlock request sent but not attempting auth.";
- return;
- }
- PA_LOG(INFO) << "Received unlock response from device: "
- << (success ? "yes" : "no") << ".";
- if (success && GetMessenger()) {
- GetMessenger()->DispatchUnlockEvent();
- } else {
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kFailedToSendUnlockRequest);
- }
- }
- void UnlockManagerImpl::OnDisconnected() {
- if (is_attempting_auth_) {
- RecordAuthResultFailure(
- screenlock_type_,
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kAuthenticatedChannelDropped);
- } else if (is_performing_initial_scan_) {
- RecordGetRemoteStatusResultFailure(
- screenlock_type_,
- GetRemoteStatusResultFailureReason::kAuthenticatedChannelDropped);
- }
- if (GetMessenger())
- GetMessenger()->RemoveObserver(this);
- }
- void UnlockManagerImpl::OnProximityStateChanged() {
- PA_LOG(VERBOSE) << "Proximity state changed.";
- UpdateLockScreen();
- }
- void UnlockManagerImpl::OnBluetoothAdapterInitialized(
- scoped_refptr<device::BluetoothAdapter> adapter) {
- bluetooth_adapter_ = adapter;
- bluetooth_adapter_->AddObserver(this);
- }
- void UnlockManagerImpl::AdapterPresentChanged(device::BluetoothAdapter* adapter,
- bool present) {
- if (!IsBluetoothAdapterRecoveringFromSuspend())
- OnBluetoothAdapterPresentAndPoweredChanged();
- }
- void UnlockManagerImpl::AdapterPoweredChanged(device::BluetoothAdapter* adapter,
- bool powered) {
- if (!IsBluetoothAdapterRecoveringFromSuspend())
- OnBluetoothAdapterPresentAndPoweredChanged();
- }
- void UnlockManagerImpl::SuspendImminent(
- power_manager::SuspendImminent::Reason reason) {
- // TODO(crbug.com/986896): For a short time window after resuming from
- // suspension, BluetoothAdapter returns incorrect presence and power values.
- // Cache the correct values now, in case we need to check those values during
- // that time window when the device resumes.
- was_bluetooth_present_and_powered_before_last_suspend_ =
- IsBluetoothPresentAndPowered();
- bluetooth_suspension_recovery_timer_->Stop();
- }
- void UnlockManagerImpl::SuspendDone(base::TimeDelta sleep_duration) {
- bluetooth_suspension_recovery_timer_->Start(
- FROM_HERE, kBluetoothAdapterResumeMaxDuration,
- base::BindOnce(
- &UnlockManagerImpl::OnBluetoothAdapterPresentAndPoweredChanged,
- weak_ptr_factory_.GetWeakPtr()));
- // The next scan after resuming is expected to be triggered by calling
- // SetRemoteDeviceLifeCycle().
- }
- bool UnlockManagerImpl::IsBluetoothPresentAndPowered() const {
- // TODO(crbug.com/986896): If the BluetoothAdapter is still "resuming after
- // suspension" at this time, it's prone to this bug, meaning we cannot trust
- // its returned presence and power values. If this is the case, depend on
- // the cached |was_bluetooth_present_and_powered_before_last_suspend_| to
- // signal if Bluetooth is enabled; otherwise, directly check request values
- // from BluetoothAdapter. Remove this check once the bug is fixed.
- if (IsBluetoothAdapterRecoveringFromSuspend())
- return was_bluetooth_present_and_powered_before_last_suspend_;
- return bluetooth_adapter_ && bluetooth_adapter_->IsPresent() &&
- bluetooth_adapter_->IsPowered();
- }
- void UnlockManagerImpl::OnBluetoothAdapterPresentAndPoweredChanged() {
- DCHECK(!IsBluetoothAdapterRecoveringFromSuspend());
- if (IsBluetoothPresentAndPowered()) {
- if (!is_performing_initial_scan_ &&
- !is_bluetooth_connection_to_phone_active_) {
- SetIsPerformingInitialScan(true /* is_performing_initial_scan */);
- }
- return;
- }
- if (is_performing_initial_scan_) {
- if (is_bluetooth_connection_to_phone_active_ &&
- !has_received_first_remote_status_) {
- RecordGetRemoteStatusResultFailure(
- screenlock_type_,
- GetRemoteStatusResultFailureReason::kCanceledBluetoothDisabled);
- } else {
- RecordFindAndConnectToHostResult(
- screenlock_type_,
- FindAndConnectToHostResult::kCanceledBluetoothDisabled);
- }
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- return;
- }
- // If Bluetooth is off but no initial scan is active, still ensure that the
- // lock screen UI reflects that Bluetooth is off.
- UpdateLockScreen();
- }
- bool UnlockManagerImpl::IsBluetoothAdapterRecoveringFromSuspend() const {
- return bluetooth_suspension_recovery_timer_->IsRunning();
- }
- void UnlockManagerImpl::AttemptToStartRemoteDeviceLifecycle() {
- if (IsBluetoothPresentAndPowered() && life_cycle_ &&
- life_cycle_->GetState() == RemoteDeviceLifeCycle::State::STOPPED) {
- // If Bluetooth is disabled after this, |life_cycle_| will be notified by
- // SecureChannel that the connection attempt failed. From that point on,
- // |life_cycle_| will wait to be started again by UnlockManager.
- life_cycle_->Start();
- }
- }
- void UnlockManagerImpl::OnAuthAttempted(mojom::AuthType auth_type) {
- if (is_attempting_auth_) {
- PA_LOG(VERBOSE) << "Already attempting auth.";
- return;
- }
- if (auth_type != mojom::AuthType::USER_CLICK)
- return;
- is_attempting_auth_ = true;
- if (!life_cycle_ || !GetMessenger()) {
- PA_LOG(ERROR) << "No life_cycle active when auth was attempted";
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kNoPendingOrActiveHost);
- UpdateLockScreen();
- return;
- }
- if (!IsUnlockAllowed()) {
- FinalizeAuthAttempt(
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kUnlockNotAllowed);
- UpdateLockScreen();
- return;
- }
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(
- &UnlockManagerImpl::FinalizeAuthAttempt,
- reject_auth_attempt_weak_ptr_factory_.GetWeakPtr(),
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason::
- kAuthAttemptTimedOut),
- kAuthAttemptTimeout);
- if (screenlock_type_ == ProximityAuthSystem::SIGN_IN) {
- SendSignInChallenge();
- } else {
- GetMessenger()->RequestUnlock();
- }
- }
- void UnlockManagerImpl::CancelConnectionAttempt() {
- PA_LOG(VERBOSE) << "User entered password.";
- bluetooth_suspension_recovery_timer_->Stop();
- // Note: There is no need to record metrics here if Bluetooth isn't present
- // and powered; that has already been handled at this point in
- // OnBluetoothAdapterPresentAndPoweredChanged().
- if (!IsBluetoothPresentAndPowered())
- return;
- if (is_performing_initial_scan_) {
- if (is_bluetooth_connection_to_phone_active_ &&
- !has_received_first_remote_status_) {
- RecordGetRemoteStatusResultFailure(
- screenlock_type_,
- GetRemoteStatusResultFailureReason::kCanceledUserEnteredPassword);
- } else {
- RecordFindAndConnectToHostResult(
- screenlock_type_,
- FindAndConnectToHostResult::kCanceledUserEnteredPassword);
- }
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- }
- }
- std::unique_ptr<ProximityMonitor> UnlockManagerImpl::CreateProximityMonitor(
- RemoteDeviceLifeCycle* life_cycle) {
- return std::make_unique<ProximityMonitorImpl>(life_cycle->GetRemoteDevice(),
- life_cycle->GetChannel());
- }
- void UnlockManagerImpl::SendSignInChallenge() {
- if (!life_cycle_ || !GetMessenger()) {
- PA_LOG(ERROR) << "Not ready to send sign-in challenge";
- return;
- }
- if (!GetMessenger()->GetChannel()) {
- PA_LOG(ERROR) << "Channel is not ready to send sign-in challenge.";
- return;
- }
- GetMessenger()->GetChannel()->GetConnectionMetadata(
- base::BindOnce(&UnlockManagerImpl::OnGetConnectionMetadata,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void UnlockManagerImpl::OnGetConnectionMetadata(
- ash::secure_channel::mojom::ConnectionMetadataPtr connection_metadata_ptr) {
- ash::multidevice::RemoteDeviceRef remote_device =
- life_cycle_->GetRemoteDevice();
- proximity_auth_client_->GetChallengeForUserAndDevice(
- remote_device.user_email(), remote_device.public_key(),
- connection_metadata_ptr->channel_binding_data,
- base::BindOnce(&UnlockManagerImpl::OnGotSignInChallenge,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void UnlockManagerImpl::OnGotSignInChallenge(const std::string& challenge) {
- PA_LOG(VERBOSE) << "Got sign-in challenge, sending for decryption...";
- if (GetMessenger())
- GetMessenger()->RequestDecryption(challenge);
- }
- SmartLockState UnlockManagerImpl::GetSmartLockState() {
- if (!life_cycle_)
- return SmartLockState::kInactive;
- if (!IsBluetoothPresentAndPowered())
- return SmartLockState::kBluetoothDisabled;
- if (IsUnlockAllowed())
- return SmartLockState::kPhoneAuthenticated;
- RemoteDeviceLifeCycle::State life_cycle_state = life_cycle_->GetState();
- if (life_cycle_state == RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED)
- return SmartLockState::kPhoneNotAuthenticated;
- if (is_performing_initial_scan_)
- return SmartLockState::kConnectingToPhone;
- Messenger* messenger = GetMessenger();
- // Show a timeout state if we can not connect to the remote device in a
- // reasonable amount of time.
- if (!messenger)
- return SmartLockState::kPhoneNotFound;
- // If the RSSI is too low, then the remote device is nowhere near the local
- // device. This message should take priority over messages about Smart Lock
- // states.
- if (proximity_monitor_ && !proximity_monitor_->IsUnlockAllowed()) {
- if (remote_screenlock_state_ &&
- *remote_screenlock_state_ == RemoteScreenlockState::UNLOCKED) {
- return SmartLockState::kPhoneFoundUnlockedAndDistant;
- } else {
- return SmartLockState::kPhoneFoundLockedAndDistant;
- }
- }
- if (remote_screenlock_state_) {
- switch (*remote_screenlock_state_) {
- case RemoteScreenlockState::DISABLED:
- return SmartLockState::kPhoneNotLockable;
- case RemoteScreenlockState::LOCKED:
- return SmartLockState::kPhoneFoundLockedAndProximate;
- case RemoteScreenlockState::PRIMARY_USER_ABSENT:
- return SmartLockState::kPrimaryUserAbsent;
- case RemoteScreenlockState::UNKNOWN:
- case RemoteScreenlockState::UNLOCKED:
- // Handled by the code below.
- break;
- }
- }
- if (messenger) {
- PA_LOG(WARNING) << "Connection to host established, but remote screenlock "
- << "state was either malformed or not received.";
- }
- // TODO(crbug.com/1233587): Add more granular error states
- return SmartLockState::kPhoneNotFound;
- }
- void UnlockManagerImpl::UpdateLockScreen() {
- AttemptToStartRemoteDeviceLifecycle();
- SmartLockState new_state = GetSmartLockState();
- if (smartlock_state_ == new_state)
- return;
- PA_LOG(INFO) << "Updating Smart Lock state from " << smartlock_state_
- << " to " << new_state;
- RecordFirstStatusShownToUser(new_state);
- proximity_auth_client_->UpdateSmartLockState(new_state);
- smartlock_state_ = new_state;
- }
- void UnlockManagerImpl::SetIsPerformingInitialScan(
- bool is_performing_initial_scan) {
- PA_LOG(VERBOSE) << "Initial scan state is ["
- << (is_performing_initial_scan_ ? "active" : "inactive")
- << "]. Requesting state ["
- << (is_performing_initial_scan ? "active" : "inactive")
- << "].";
- is_performing_initial_scan_ = is_performing_initial_scan;
- // Clear the waking up state after a timeout.
- initial_scan_timeout_weak_ptr_factory_.InvalidateWeakPtrs();
- if (is_performing_initial_scan_) {
- initial_scan_start_time_ = base::DefaultClock::GetInstance()->Now();
- has_received_first_remote_status_ = false;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&UnlockManagerImpl::OnInitialScanTimeout,
- initial_scan_timeout_weak_ptr_factory_.GetWeakPtr()),
- kWakingUpDuration);
- }
- UpdateLockScreen();
- }
- void UnlockManagerImpl::OnInitialScanTimeout() {
- // Note: There is no need to record metrics here if Bluetooth isn't present
- // and powered; that has already been handled at this point in
- // OnBluetoothAdapterPresentAndPoweredChanged().
- if (!IsBluetoothPresentAndPowered())
- return;
- if (is_bluetooth_connection_to_phone_active_) {
- PA_LOG(ERROR) << "Successfully connected to host, but it did not provide "
- "remote status update.";
- RecordGetRemoteStatusResultFailure(
- screenlock_type_, GetRemoteStatusResultFailureReason::
- kTimedOutDidNotReceiveRemoteStatusUpdate);
- } else {
- PA_LOG(INFO) << "Initial scan for host returned no result.";
- RecordFindAndConnectToHostResult(screenlock_type_,
- FindAndConnectToHostResult::kTimedOut);
- }
- SetIsPerformingInitialScan(false /* is_performing_initial_scan */);
- }
- void UnlockManagerImpl::FinalizeAuthAttempt(
- const absl::optional<
- SmartLockMetricsRecorder::SmartLockAuthResultFailureReason>& error) {
- if (error) {
- RecordAuthResultFailure(screenlock_type_, *error);
- }
- if (!is_attempting_auth_)
- return;
- // Cancel the pending task to time out the auth attempt.
- reject_auth_attempt_weak_ptr_factory_.InvalidateWeakPtrs();
- bool should_accept = !error;
- if (should_accept && proximity_monitor_)
- proximity_monitor_->RecordProximityMetricsOnAuthSuccess();
- is_attempting_auth_ = false;
- if (screenlock_type_ == ProximityAuthSystem::SIGN_IN) {
- PA_LOG(VERBOSE) << "Finalizing sign-in...";
- proximity_auth_client_->FinalizeSignin(
- should_accept && sign_in_secret_ ? *sign_in_secret_ : std::string());
- } else {
- PA_LOG(VERBOSE) << "Finalizing unlock...";
- proximity_auth_client_->FinalizeUnlock(should_accept);
- }
- }
- UnlockManagerImpl::RemoteScreenlockState
- UnlockManagerImpl::GetScreenlockStateFromRemoteUpdate(
- RemoteStatusUpdate update) {
- switch (update.secure_screen_lock_state) {
- case SECURE_SCREEN_LOCK_DISABLED:
- return RemoteScreenlockState::DISABLED;
- case SECURE_SCREEN_LOCK_ENABLED:
- if (update.user_presence == USER_PRESENCE_SECONDARY ||
- update.user_presence == USER_PRESENCE_BACKGROUND) {
- return RemoteScreenlockState::PRIMARY_USER_ABSENT;
- }
- if (update.user_presence == USER_PRESENT)
- return RemoteScreenlockState::UNLOCKED;
- return RemoteScreenlockState::LOCKED;
- case SECURE_SCREEN_LOCK_STATE_UNKNOWN:
- return RemoteScreenlockState::UNKNOWN;
- }
- NOTREACHED();
- return RemoteScreenlockState::UNKNOWN;
- }
- Messenger* UnlockManagerImpl::GetMessenger() {
- // TODO(tengs): We should use a weak pointer to hold the Messenger instance
- // instead.
- if (!life_cycle_)
- return nullptr;
- return life_cycle_->GetMessenger();
- }
- void UnlockManagerImpl::RecordFirstRemoteStatusReceived(bool unlockable) {
- if (has_received_first_remote_status_)
- return;
- has_received_first_remote_status_ = true;
- RecordGetRemoteStatusResultSuccess(screenlock_type_);
- if (initial_scan_start_time_.is_null() ||
- attempt_get_remote_status_start_time_.is_null()) {
- PA_LOG(WARNING) << "Attempted to RecordFirstRemoteStatusReceived() "
- "without initial timestamps recorded.";
- NOTREACHED();
- return;
- }
- const std::string histogram_status_suffix =
- GetHistogramStatusSuffix(unlockable);
- base::Time now = base::DefaultClock::GetInstance()->Now();
- base::TimeDelta start_scan_to_receive_first_remote_status_duration =
- now - initial_scan_start_time_;
- base::TimeDelta authentication_to_receive_first_remote_status_duration =
- now - attempt_get_remote_status_start_time_;
- if (screenlock_type_ == ProximityAuthSystem::SESSION_LOCK) {
- RecordExtendedDurationTimerMetric(
- "SmartLock.Performance.StartScanToReceiveFirstRemoteStatusDuration."
- "Unlock",
- start_scan_to_receive_first_remote_status_duration);
- RecordExtendedDurationTimerMetric(
- "SmartLock.Performance.StartScanToReceiveFirstRemoteStatusDuration."
- "Unlock." +
- histogram_status_suffix,
- start_scan_to_receive_first_remote_status_duration);
- // This should be much less than 10 seconds, so use UmaHistogramTimes.
- base::UmaHistogramTimes(
- "SmartLock.Performance."
- "AuthenticationToReceiveFirstRemoteStatusDuration.Unlock",
- authentication_to_receive_first_remote_status_duration);
- base::UmaHistogramTimes(
- "SmartLock.Performance."
- "AuthenticationToReceiveFirstRemoteStatusDuration.Unlock." +
- histogram_status_suffix,
- authentication_to_receive_first_remote_status_duration);
- }
- }
- void UnlockManagerImpl::RecordFirstStatusShownToUser(SmartLockState new_state) {
- absl::optional<FirstSmartLockStatus> first_status =
- GetFirstSmartLockStatus(new_state);
- if (!first_status.has_value()) {
- return;
- }
- if (has_user_been_shown_first_status_) {
- return;
- }
- has_user_been_shown_first_status_ = true;
- if (show_lock_screen_time_.is_null()) {
- PA_LOG(WARNING) << "Attempted to RecordFirstStatusShownToUser() "
- "without initial timestamp recorded.";
- NOTREACHED();
- return;
- }
- base::UmaHistogramEnumeration("SmartLock.FirstStatusToUser",
- first_status.value());
- base::Time now = base::DefaultClock::GetInstance()->Now();
- base::TimeDelta show_lock_screen_to_show_first_status_to_user_duration =
- now - show_lock_screen_time_;
- if (screenlock_type_ == ProximityAuthSystem::SESSION_LOCK) {
- RecordExtendedDurationTimerMetric(
- "SmartLock.Performance.ShowLockScreenToShowFirstStatusToUserDuration."
- "Unlock",
- show_lock_screen_to_show_first_status_to_user_duration);
- if (new_state == SmartLockState::kPhoneAuthenticated) {
- RecordExtendedDurationTimerMetric(
- "SmartLock.Performance.ShowLockScreenToShowFirstStatusToUserDuration."
- "Unlock.Unlockable",
- show_lock_screen_to_show_first_status_to_user_duration);
- } else if (HasCommunicatedWithPhone(new_state)) {
- // Only log to Unlock.Other if we aren't in an unlockable state since
- // that's covered by the other metric, and only if we are in a state that
- // indicates we were able to communicate with the phone over Bluetooth
- // since in all other cases the time to show the first status is highly
- // deterministic.
- RecordExtendedDurationTimerMetric(
- "SmartLock.Performance.ShowLockScreenToShowFirstStatusToUserDuration."
- "Unlock.Other",
- show_lock_screen_to_show_first_status_to_user_duration);
- }
- }
- }
- void UnlockManagerImpl::ResetPerformanceMetricsTimestamps() {
- show_lock_screen_time_ = base::Time();
- initial_scan_start_time_ = base::Time();
- attempt_get_remote_status_start_time_ = base::Time();
- }
- void UnlockManagerImpl::SetBluetoothSuspensionRecoveryTimerForTesting(
- std::unique_ptr<base::OneShotTimer> timer) {
- bluetooth_suspension_recovery_timer_ = std::move(timer);
- }
- void UnlockManagerImpl::RecordGetRemoteStatusResultSuccess(
- ProximityAuthSystem::ScreenlockType screenlock_type,
- bool success) {
- base::UmaHistogramBoolean("SmartLock.GetRemoteStatus." +
- GetHistogramScreenLockTypeName(screenlock_type),
- success);
- if (screenlock_type == ProximityAuthSystem::SESSION_LOCK) {
- get_remote_status_unlock_success_ = success;
- }
- }
- void UnlockManagerImpl::RecordGetRemoteStatusResultFailure(
- ProximityAuthSystem::ScreenlockType screenlock_type,
- GetRemoteStatusResultFailureReason failure_reason) {
- RecordGetRemoteStatusResultSuccess(screenlock_type, false /* success */);
- base::UmaHistogramEnumeration(
- "SmartLock.GetRemoteStatus." +
- GetHistogramScreenLockTypeName(screenlock_type) + ".Failure",
- failure_reason);
- if (screenlock_type == ProximityAuthSystem::SESSION_LOCK) {
- get_remote_status_unlock_failure_reason_ = failure_reason;
- }
- }
- std::string UnlockManagerImpl::GetRemoteStatusResultFailureReasonToString(
- GetRemoteStatusResultFailureReason reason) {
- switch (reason) {
- case GetRemoteStatusResultFailureReason::kCanceledBluetoothDisabled:
- return "CanceledBluetoothDisabled";
- case GetRemoteStatusResultFailureReason::
- kDeprecatedTimedOutCouldNotEstablishAuthenticatedChannel:
- return "DeprecatedTimedOutCouldNotEstablishAuthenticatedChannel";
- case GetRemoteStatusResultFailureReason::
- kTimedOutDidNotReceiveRemoteStatusUpdate:
- return "TimedOutDidNotReceiveRemoteStatusUpdate";
- case GetRemoteStatusResultFailureReason::
- kDeprecatedUserEnteredPasswordWhileBluetoothDisabled:
- return "DeprecatedUserEnteredPasswordWhileBluetoothDisabled";
- case GetRemoteStatusResultFailureReason::kCanceledUserEnteredPassword:
- return "CanceledUserEnteredPassword";
- case GetRemoteStatusResultFailureReason::kAuthenticatedChannelDropped:
- return "AuthenticatedChannelDropped";
- }
- }
- std::string UnlockManagerImpl::GetLastRemoteStatusUnlockForLogging() {
- if (!get_remote_status_unlock_success_.has_value()) {
- return kGetRemoteStatusNone;
- }
- if (*get_remote_status_unlock_success_) {
- return kGetRemoteStatusSuccess;
- }
- if (!get_remote_status_unlock_failure_reason_.has_value()) {
- return kGetRemoteStatusNone;
- }
- return GetRemoteStatusResultFailureReasonToString(
- *get_remote_status_unlock_failure_reason_);
- }
- } // namespace proximity_auth
|