proximity_monitor_impl.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright 2015 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. #include "ash/components/proximity_auth/proximity_monitor_impl.h"
  5. #include <math.h>
  6. #include <memory>
  7. #include <utility>
  8. #include "ash/components/multidevice/logging/logging.h"
  9. #include "ash/components/proximity_auth/metrics.h"
  10. #include "ash/services/secure_channel/public/cpp/client/client_channel.h"
  11. #include "base/bind.h"
  12. #include "base/threading/thread_task_runner_handle.h"
  13. #include "base/time/time.h"
  14. #include "device/bluetooth/bluetooth_adapter.h"
  15. #include "device/bluetooth/bluetooth_adapter_factory.h"
  16. namespace proximity_auth {
  17. // The time to wait, in milliseconds, between proximity polling iterations.
  18. const int kPollingTimeoutMs = 250;
  19. // The weight of the most recent RSSI sample.
  20. const double kRssiSampleWeight = 0.3;
  21. // RSSI must be greater than this value to consider the host proximate, and
  22. // allow unlock.
  23. const int kRssiThreshold = -70;
  24. ProximityMonitorImpl::ProximityMonitorImpl(
  25. ash::multidevice::RemoteDeviceRef remote_device,
  26. ash::secure_channel::ClientChannel* channel)
  27. : remote_device_(remote_device),
  28. channel_(channel),
  29. remote_device_is_in_proximity_(false),
  30. is_active_(false) {
  31. if (device::BluetoothAdapterFactory::IsBluetoothSupported()) {
  32. device::BluetoothAdapterFactory::Get()->GetAdapter(
  33. base::BindOnce(&ProximityMonitorImpl::OnAdapterInitialized,
  34. weak_ptr_factory_.GetWeakPtr()));
  35. } else {
  36. PA_LOG(ERROR) << "[Proximity] Proximity monitoring unavailable: "
  37. << "Bluetooth is unsupported on this platform.";
  38. }
  39. }
  40. ProximityMonitorImpl::~ProximityMonitorImpl() {}
  41. void ProximityMonitorImpl::Start() {
  42. is_active_ = true;
  43. UpdatePollingState();
  44. }
  45. void ProximityMonitorImpl::Stop() {
  46. is_active_ = false;
  47. ClearProximityState();
  48. UpdatePollingState();
  49. }
  50. bool ProximityMonitorImpl::IsUnlockAllowed() const {
  51. return remote_device_is_in_proximity_;
  52. }
  53. void ProximityMonitorImpl::RecordProximityMetricsOnAuthSuccess() {
  54. double rssi_rolling_average = rssi_rolling_average_
  55. ? *rssi_rolling_average_
  56. : metrics::kUnknownProximityValue;
  57. std::string remote_device_model = metrics::kUnknownDeviceModel;
  58. ash::multidevice::RemoteDeviceRef remote_device = remote_device_;
  59. if (!remote_device.name().empty())
  60. remote_device_model = remote_device.name();
  61. metrics::RecordAuthProximityRollingRssi(round(rssi_rolling_average));
  62. metrics::RecordAuthProximityRemoteDeviceModelHash(remote_device_model);
  63. }
  64. void ProximityMonitorImpl::OnAdapterInitialized(
  65. scoped_refptr<device::BluetoothAdapter> adapter) {
  66. bluetooth_adapter_ = adapter;
  67. UpdatePollingState();
  68. }
  69. void ProximityMonitorImpl::UpdatePollingState() {
  70. if (ShouldPoll()) {
  71. // If there is a polling iteration already scheduled, wait for it.
  72. if (polling_weak_ptr_factory_.HasWeakPtrs())
  73. return;
  74. // Polling can re-entrantly call back into this method, so make sure to
  75. // schedule the next polling iteration prior to executing the current one.
  76. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  77. FROM_HERE,
  78. base::BindOnce(
  79. &ProximityMonitorImpl::PerformScheduledUpdatePollingState,
  80. polling_weak_ptr_factory_.GetWeakPtr()),
  81. base::Milliseconds(kPollingTimeoutMs));
  82. Poll();
  83. } else {
  84. polling_weak_ptr_factory_.InvalidateWeakPtrs();
  85. remote_device_is_in_proximity_ = false;
  86. }
  87. }
  88. void ProximityMonitorImpl::PerformScheduledUpdatePollingState() {
  89. polling_weak_ptr_factory_.InvalidateWeakPtrs();
  90. UpdatePollingState();
  91. }
  92. bool ProximityMonitorImpl::ShouldPoll() const {
  93. return is_active_ && bluetooth_adapter_;
  94. }
  95. void ProximityMonitorImpl::Poll() {
  96. DCHECK(ShouldPoll());
  97. if (channel_->is_disconnected()) {
  98. PA_LOG(ERROR) << "Channel is disconnected.";
  99. ClearProximityState();
  100. return;
  101. }
  102. channel_->GetConnectionMetadata(
  103. base::BindOnce(&ProximityMonitorImpl::OnGetConnectionMetadata,
  104. weak_ptr_factory_.GetWeakPtr()));
  105. }
  106. void ProximityMonitorImpl::OnGetConnectionMetadata(
  107. ash::secure_channel::mojom::ConnectionMetadataPtr connection_metadata) {
  108. if (connection_metadata->bluetooth_connection_metadata)
  109. OnGetRssi(connection_metadata->bluetooth_connection_metadata->current_rssi);
  110. else
  111. OnGetRssi(absl::nullopt);
  112. }
  113. void ProximityMonitorImpl::OnGetRssi(const absl::optional<int32_t>& rssi) {
  114. if (!is_active_) {
  115. PA_LOG(VERBOSE) << "Received RSSI after stopping.";
  116. return;
  117. }
  118. if (rssi) {
  119. AddSample(*rssi);
  120. } else {
  121. PA_LOG(WARNING) << "Received invalid RSSI value.";
  122. rssi_rolling_average_.reset();
  123. CheckForProximityStateChange();
  124. }
  125. }
  126. void ProximityMonitorImpl::ClearProximityState() {
  127. if (is_active_ && remote_device_is_in_proximity_)
  128. NotifyProximityStateChanged();
  129. remote_device_is_in_proximity_ = false;
  130. rssi_rolling_average_.reset();
  131. }
  132. void ProximityMonitorImpl::AddSample(int32_t rssi) {
  133. double weight = kRssiSampleWeight;
  134. if (!rssi_rolling_average_) {
  135. rssi_rolling_average_ = std::make_unique<double>(rssi);
  136. } else {
  137. *rssi_rolling_average_ =
  138. weight * rssi + (1 - weight) * (*rssi_rolling_average_);
  139. }
  140. CheckForProximityStateChange();
  141. }
  142. void ProximityMonitorImpl::CheckForProximityStateChange() {
  143. bool is_now_in_proximity =
  144. rssi_rolling_average_ && *rssi_rolling_average_ > kRssiThreshold;
  145. if (rssi_rolling_average_ && !is_now_in_proximity) {
  146. PA_LOG(VERBOSE) << "Not in proximity. Rolling RSSI average: "
  147. << *rssi_rolling_average_;
  148. }
  149. if (remote_device_is_in_proximity_ != is_now_in_proximity) {
  150. PA_LOG(VERBOSE) << "[Proximity] Updated proximity state: "
  151. << (is_now_in_proximity ? "proximate" : "distant");
  152. remote_device_is_in_proximity_ = is_now_in_proximity;
  153. NotifyProximityStateChanged();
  154. }
  155. }
  156. } // namespace proximity_auth