123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- // 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/proximity_monitor_impl.h"
- #include <math.h>
- #include <memory>
- #include <utility>
- #include "ash/components/multidevice/logging/logging.h"
- #include "ash/components/proximity_auth/metrics.h"
- #include "ash/services/secure_channel/public/cpp/client/client_channel.h"
- #include "base/bind.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "device/bluetooth/bluetooth_adapter.h"
- #include "device/bluetooth/bluetooth_adapter_factory.h"
- namespace proximity_auth {
- // The time to wait, in milliseconds, between proximity polling iterations.
- const int kPollingTimeoutMs = 250;
- // The weight of the most recent RSSI sample.
- const double kRssiSampleWeight = 0.3;
- // RSSI must be greater than this value to consider the host proximate, and
- // allow unlock.
- const int kRssiThreshold = -70;
- ProximityMonitorImpl::ProximityMonitorImpl(
- ash::multidevice::RemoteDeviceRef remote_device,
- ash::secure_channel::ClientChannel* channel)
- : remote_device_(remote_device),
- channel_(channel),
- remote_device_is_in_proximity_(false),
- is_active_(false) {
- if (device::BluetoothAdapterFactory::IsBluetoothSupported()) {
- device::BluetoothAdapterFactory::Get()->GetAdapter(
- base::BindOnce(&ProximityMonitorImpl::OnAdapterInitialized,
- weak_ptr_factory_.GetWeakPtr()));
- } else {
- PA_LOG(ERROR) << "[Proximity] Proximity monitoring unavailable: "
- << "Bluetooth is unsupported on this platform.";
- }
- }
- ProximityMonitorImpl::~ProximityMonitorImpl() {}
- void ProximityMonitorImpl::Start() {
- is_active_ = true;
- UpdatePollingState();
- }
- void ProximityMonitorImpl::Stop() {
- is_active_ = false;
- ClearProximityState();
- UpdatePollingState();
- }
- bool ProximityMonitorImpl::IsUnlockAllowed() const {
- return remote_device_is_in_proximity_;
- }
- void ProximityMonitorImpl::RecordProximityMetricsOnAuthSuccess() {
- double rssi_rolling_average = rssi_rolling_average_
- ? *rssi_rolling_average_
- : metrics::kUnknownProximityValue;
- std::string remote_device_model = metrics::kUnknownDeviceModel;
- ash::multidevice::RemoteDeviceRef remote_device = remote_device_;
- if (!remote_device.name().empty())
- remote_device_model = remote_device.name();
- metrics::RecordAuthProximityRollingRssi(round(rssi_rolling_average));
- metrics::RecordAuthProximityRemoteDeviceModelHash(remote_device_model);
- }
- void ProximityMonitorImpl::OnAdapterInitialized(
- scoped_refptr<device::BluetoothAdapter> adapter) {
- bluetooth_adapter_ = adapter;
- UpdatePollingState();
- }
- void ProximityMonitorImpl::UpdatePollingState() {
- if (ShouldPoll()) {
- // If there is a polling iteration already scheduled, wait for it.
- if (polling_weak_ptr_factory_.HasWeakPtrs())
- return;
- // Polling can re-entrantly call back into this method, so make sure to
- // schedule the next polling iteration prior to executing the current one.
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(
- &ProximityMonitorImpl::PerformScheduledUpdatePollingState,
- polling_weak_ptr_factory_.GetWeakPtr()),
- base::Milliseconds(kPollingTimeoutMs));
- Poll();
- } else {
- polling_weak_ptr_factory_.InvalidateWeakPtrs();
- remote_device_is_in_proximity_ = false;
- }
- }
- void ProximityMonitorImpl::PerformScheduledUpdatePollingState() {
- polling_weak_ptr_factory_.InvalidateWeakPtrs();
- UpdatePollingState();
- }
- bool ProximityMonitorImpl::ShouldPoll() const {
- return is_active_ && bluetooth_adapter_;
- }
- void ProximityMonitorImpl::Poll() {
- DCHECK(ShouldPoll());
- if (channel_->is_disconnected()) {
- PA_LOG(ERROR) << "Channel is disconnected.";
- ClearProximityState();
- return;
- }
- channel_->GetConnectionMetadata(
- base::BindOnce(&ProximityMonitorImpl::OnGetConnectionMetadata,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void ProximityMonitorImpl::OnGetConnectionMetadata(
- ash::secure_channel::mojom::ConnectionMetadataPtr connection_metadata) {
- if (connection_metadata->bluetooth_connection_metadata)
- OnGetRssi(connection_metadata->bluetooth_connection_metadata->current_rssi);
- else
- OnGetRssi(absl::nullopt);
- }
- void ProximityMonitorImpl::OnGetRssi(const absl::optional<int32_t>& rssi) {
- if (!is_active_) {
- PA_LOG(VERBOSE) << "Received RSSI after stopping.";
- return;
- }
- if (rssi) {
- AddSample(*rssi);
- } else {
- PA_LOG(WARNING) << "Received invalid RSSI value.";
- rssi_rolling_average_.reset();
- CheckForProximityStateChange();
- }
- }
- void ProximityMonitorImpl::ClearProximityState() {
- if (is_active_ && remote_device_is_in_proximity_)
- NotifyProximityStateChanged();
- remote_device_is_in_proximity_ = false;
- rssi_rolling_average_.reset();
- }
- void ProximityMonitorImpl::AddSample(int32_t rssi) {
- double weight = kRssiSampleWeight;
- if (!rssi_rolling_average_) {
- rssi_rolling_average_ = std::make_unique<double>(rssi);
- } else {
- *rssi_rolling_average_ =
- weight * rssi + (1 - weight) * (*rssi_rolling_average_);
- }
- CheckForProximityStateChange();
- }
- void ProximityMonitorImpl::CheckForProximityStateChange() {
- bool is_now_in_proximity =
- rssi_rolling_average_ && *rssi_rolling_average_ > kRssiThreshold;
- if (rssi_rolling_average_ && !is_now_in_proximity) {
- PA_LOG(VERBOSE) << "Not in proximity. Rolling RSSI average: "
- << *rssi_rolling_average_;
- }
- if (remote_device_is_in_proximity_ != is_now_in_proximity) {
- PA_LOG(VERBOSE) << "[Proximity] Updated proximity state: "
- << (is_now_in_proximity ? "proximate" : "distant");
- remote_device_is_in_proximity_ = is_now_in_proximity;
- NotifyProximityStateChanged();
- }
- }
- } // namespace proximity_auth
|