OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/proximity_auth/proximity_monitor_impl.h" | 5 #include "components/proximity_auth/proximity_monitor_impl.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/threading/thread_task_runner_handle.h" | 12 #include "base/threading/thread_task_runner_handle.h" |
13 #include "base/time/tick_clock.h" | 13 #include "base/time/tick_clock.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
15 #include "components/proximity_auth/logging/logging.h" | 15 #include "components/proximity_auth/logging/logging.h" |
16 #include "components/proximity_auth/metrics.h" | 16 #include "components/proximity_auth/metrics.h" |
17 #include "components/proximity_auth/proximity_monitor_observer.h" | 17 #include "components/proximity_auth/proximity_monitor_observer.h" |
18 #include "device/bluetooth/bluetooth_adapter.h" | 18 #include "device/bluetooth/bluetooth_adapter.h" |
19 #include "device/bluetooth/bluetooth_adapter_factory.h" | 19 #include "device/bluetooth/bluetooth_adapter_factory.h" |
20 | 20 |
21 using device::BluetoothDevice; | 21 using device::BluetoothDevice; |
22 | 22 |
23 namespace proximity_auth { | 23 namespace proximity_auth { |
24 | 24 |
25 // The time to wait, in milliseconds, between proximity polling iterations. | 25 // The time to wait, in milliseconds, between proximity polling iterations. |
26 const int kPollingTimeoutMs = 250; | 26 const int kPollingTimeoutMs = 250; |
27 | 27 |
28 // The RSSI threshold below which we consider the remote device to not be in | 28 // The RSSI threshold below which we consider the remote device to not be in |
29 // proximity. | 29 // proximity. |
30 const int kRssiThreshold = -5; | 30 const int kRssiThreshold = -45; |
31 | 31 |
32 // The weight of the most recent RSSI sample. | 32 // The weight of the most recent RSSI sample. |
33 const double kRssiSampleWeight = 0.3; | 33 const double kRssiSampleWeight = 0.3; |
34 | 34 |
35 ProximityMonitorImpl::ProximityMonitorImpl( | 35 ProximityMonitorImpl::ProximityMonitorImpl( |
36 const cryptauth::RemoteDevice& remote_device, | 36 cryptauth::Connection* connection, |
37 std::unique_ptr<base::TickClock> clock) | 37 std::unique_ptr<base::TickClock> clock) |
38 : remote_device_(remote_device), | 38 : connection_(connection), |
39 strategy_(Strategy::NONE), | |
40 remote_device_is_in_proximity_(false), | 39 remote_device_is_in_proximity_(false), |
41 is_active_(false), | 40 is_active_(false), |
42 clock_(std::move(clock)), | 41 clock_(std::move(clock)), |
43 polling_weak_ptr_factory_(this), | 42 polling_weak_ptr_factory_(this), |
44 weak_ptr_factory_(this) { | 43 weak_ptr_factory_(this) { |
45 if (device::BluetoothAdapterFactory::IsBluetoothSupported()) { | 44 if (device::BluetoothAdapterFactory::IsBluetoothSupported()) { |
46 device::BluetoothAdapterFactory::GetAdapter( | 45 device::BluetoothAdapterFactory::GetAdapter( |
47 base::Bind(&ProximityMonitorImpl::OnAdapterInitialized, | 46 base::Bind(&ProximityMonitorImpl::OnAdapterInitialized, |
48 weak_ptr_factory_.GetWeakPtr())); | 47 weak_ptr_factory_.GetWeakPtr())); |
49 } else { | 48 } else { |
50 PA_LOG(ERROR) << "[Proximity] Proximity monitoring unavailable: " | 49 PA_LOG(ERROR) << "[Proximity] Proximity monitoring unavailable: " |
51 << "Bluetooth is unsupported on this platform."; | 50 << "Bluetooth is unsupported on this platform."; |
52 } | 51 } |
53 | |
54 // TODO(isherman): Test prefs to set the strategy. Need to read from "Local | |
55 // State" prefs on the sign-in screen, and per-user prefs on the lock screen. | |
56 // TODO(isherman): Unlike in the JS app, destroy and recreate the proximity | |
57 // monitor when the connection state changes. | |
58 } | 52 } |
59 | 53 |
60 ProximityMonitorImpl::~ProximityMonitorImpl() { | 54 ProximityMonitorImpl::~ProximityMonitorImpl() { |
61 } | 55 } |
62 | 56 |
63 void ProximityMonitorImpl::Start() { | 57 void ProximityMonitorImpl::Start() { |
64 is_active_ = true; | 58 is_active_ = true; |
65 UpdatePollingState(); | 59 UpdatePollingState(); |
66 } | 60 } |
67 | 61 |
68 void ProximityMonitorImpl::Stop() { | 62 void ProximityMonitorImpl::Stop() { |
69 is_active_ = false; | 63 is_active_ = false; |
70 ClearProximityState(); | 64 ClearProximityState(); |
71 UpdatePollingState(); | 65 UpdatePollingState(); |
72 } | 66 } |
73 | 67 |
74 ProximityMonitor::Strategy ProximityMonitorImpl::GetStrategy() const { | |
75 return strategy_; | |
76 } | |
77 | |
78 bool ProximityMonitorImpl::IsUnlockAllowed() const { | 68 bool ProximityMonitorImpl::IsUnlockAllowed() const { |
79 return strategy_ == Strategy::NONE || remote_device_is_in_proximity_; | 69 return remote_device_is_in_proximity_; |
80 } | |
81 | |
82 bool ProximityMonitorImpl::IsInRssiRange() const { | |
83 return (strategy_ != Strategy::NONE && rssi_rolling_average_ && | |
84 *rssi_rolling_average_ > kRssiThreshold); | |
85 } | 70 } |
86 | 71 |
87 void ProximityMonitorImpl::RecordProximityMetricsOnAuthSuccess() { | 72 void ProximityMonitorImpl::RecordProximityMetricsOnAuthSuccess() { |
88 double rssi_rolling_average = rssi_rolling_average_ | 73 double rssi_rolling_average = rssi_rolling_average_ |
89 ? *rssi_rolling_average_ | 74 ? *rssi_rolling_average_ |
90 : metrics::kUnknownProximityValue; | 75 : metrics::kUnknownProximityValue; |
91 | 76 |
92 int last_transmit_power_delta = | |
93 last_transmit_power_reading_ | |
94 ? (last_transmit_power_reading_->transmit_power - | |
95 last_transmit_power_reading_->max_transmit_power) | |
96 : metrics::kUnknownProximityValue; | |
97 | |
98 // If no zero RSSI value has been read, then record an overflow. | |
99 base::TimeDelta time_since_last_zero_rssi; | |
100 if (last_zero_rssi_timestamp_) | |
101 time_since_last_zero_rssi = clock_->NowTicks() - *last_zero_rssi_timestamp_; | |
102 else | |
103 time_since_last_zero_rssi = base::TimeDelta::FromDays(100); | |
104 | |
105 std::string remote_device_model = metrics::kUnknownDeviceModel; | 77 std::string remote_device_model = metrics::kUnknownDeviceModel; |
106 if (remote_device_.name != remote_device_.bluetooth_address) | 78 cryptauth::RemoteDevice remote_device = connection_->remote_device(); |
107 remote_device_model = remote_device_.name; | 79 if (!remote_device.name.empty()) |
| 80 remote_device_model = remote_device.name; |
108 | 81 |
109 metrics::RecordAuthProximityRollingRssi(round(rssi_rolling_average)); | 82 metrics::RecordAuthProximityRollingRssi(round(rssi_rolling_average)); |
110 metrics::RecordAuthProximityTransmitPowerDelta(last_transmit_power_delta); | |
111 metrics::RecordAuthProximityTimeSinceLastZeroRssi(time_since_last_zero_rssi); | |
112 metrics::RecordAuthProximityRemoteDeviceModelHash(remote_device_model); | 83 metrics::RecordAuthProximityRemoteDeviceModelHash(remote_device_model); |
113 } | 84 } |
114 | 85 |
115 void ProximityMonitorImpl::AddObserver(ProximityMonitorObserver* observer) { | 86 void ProximityMonitorImpl::AddObserver(ProximityMonitorObserver* observer) { |
116 observers_.AddObserver(observer); | 87 observers_.AddObserver(observer); |
117 } | 88 } |
118 | 89 |
119 void ProximityMonitorImpl::RemoveObserver(ProximityMonitorObserver* observer) { | 90 void ProximityMonitorImpl::RemoveObserver(ProximityMonitorObserver* observer) { |
120 observers_.RemoveObserver(observer); | 91 observers_.RemoveObserver(observer); |
121 } | 92 } |
122 | 93 |
123 void ProximityMonitorImpl::SetStrategy(Strategy strategy) { | |
124 if (strategy_ == strategy) | |
125 return; | |
126 strategy_ = strategy; | |
127 CheckForProximityStateChange(); | |
128 UpdatePollingState(); | |
129 } | |
130 | |
131 ProximityMonitorImpl::TransmitPowerReading::TransmitPowerReading( | |
132 int transmit_power, | |
133 int max_transmit_power) | |
134 : transmit_power(transmit_power), max_transmit_power(max_transmit_power) { | |
135 } | |
136 | |
137 bool ProximityMonitorImpl::TransmitPowerReading::IsInProximity() const { | |
138 return transmit_power < max_transmit_power; | |
139 } | |
140 | |
141 void ProximityMonitorImpl::OnAdapterInitialized( | 94 void ProximityMonitorImpl::OnAdapterInitialized( |
142 scoped_refptr<device::BluetoothAdapter> adapter) { | 95 scoped_refptr<device::BluetoothAdapter> adapter) { |
143 bluetooth_adapter_ = adapter; | 96 bluetooth_adapter_ = adapter; |
144 UpdatePollingState(); | 97 UpdatePollingState(); |
145 } | 98 } |
146 | 99 |
147 void ProximityMonitorImpl::UpdatePollingState() { | 100 void ProximityMonitorImpl::UpdatePollingState() { |
148 if (ShouldPoll()) { | 101 if (ShouldPoll()) { |
149 // If there is a polling iteration already scheduled, wait for it. | 102 // If there is a polling iteration already scheduled, wait for it. |
150 if (polling_weak_ptr_factory_.HasWeakPtrs()) | 103 if (polling_weak_ptr_factory_.HasWeakPtrs()) |
(...skipping 12 matching lines...) Expand all Loading... |
163 remote_device_is_in_proximity_ = false; | 116 remote_device_is_in_proximity_ = false; |
164 } | 117 } |
165 } | 118 } |
166 | 119 |
167 void ProximityMonitorImpl::PerformScheduledUpdatePollingState() { | 120 void ProximityMonitorImpl::PerformScheduledUpdatePollingState() { |
168 polling_weak_ptr_factory_.InvalidateWeakPtrs(); | 121 polling_weak_ptr_factory_.InvalidateWeakPtrs(); |
169 UpdatePollingState(); | 122 UpdatePollingState(); |
170 } | 123 } |
171 | 124 |
172 bool ProximityMonitorImpl::ShouldPoll() const { | 125 bool ProximityMonitorImpl::ShouldPoll() const { |
173 // Note: We poll even if the strategy is NONE so we can record measurements. | |
174 return is_active_ && bluetooth_adapter_; | 126 return is_active_ && bluetooth_adapter_; |
175 } | 127 } |
176 | 128 |
177 void ProximityMonitorImpl::Poll() { | 129 void ProximityMonitorImpl::Poll() { |
178 DCHECK(ShouldPoll()); | 130 DCHECK(ShouldPoll()); |
179 | 131 |
180 BluetoothDevice* device = | 132 std::string address = connection_->GetDeviceAddress(); |
181 bluetooth_adapter_->GetDevice(remote_device_.bluetooth_address); | 133 BluetoothDevice* device = bluetooth_adapter_->GetDevice(address); |
182 | 134 |
183 if (!device) { | 135 if (!device) { |
184 PA_LOG(ERROR) << "Unknown Bluetooth device with address " | 136 PA_LOG(ERROR) << "Unknown Bluetooth device with address " << address; |
185 << remote_device_.bluetooth_address; | |
186 ClearProximityState(); | 137 ClearProximityState(); |
187 return; | 138 return; |
188 } | 139 } |
189 if (!device->IsConnected()) { | 140 if (!device->IsConnected()) { |
190 PA_LOG(ERROR) << "Bluetooth device with address " | 141 PA_LOG(ERROR) << "Bluetooth device with address " << address |
191 << remote_device_.bluetooth_address << " is not connected."; | 142 << " is not connected."; |
192 ClearProximityState(); | 143 ClearProximityState(); |
193 return; | 144 return; |
194 } | 145 } |
195 | 146 |
196 device->GetConnectionInfo(base::Bind(&ProximityMonitorImpl::OnConnectionInfo, | 147 device->GetConnectionInfo(base::Bind(&ProximityMonitorImpl::OnConnectionInfo, |
197 weak_ptr_factory_.GetWeakPtr())); | 148 weak_ptr_factory_.GetWeakPtr())); |
198 } | 149 } |
199 | 150 |
200 void ProximityMonitorImpl::OnConnectionInfo( | 151 void ProximityMonitorImpl::OnConnectionInfo( |
201 const BluetoothDevice::ConnectionInfo& connection_info) { | 152 const BluetoothDevice::ConnectionInfo& connection_info) { |
202 if (!is_active_) { | 153 if (!is_active_) { |
203 PA_LOG(INFO) << "[Proximity] Got connection info after stopping"; | 154 PA_LOG(INFO) << "[Proximity] Got connection info after stopping"; |
204 return; | 155 return; |
205 } | 156 } |
206 | 157 |
207 if (connection_info.rssi != BluetoothDevice::kUnknownPower && | 158 if (connection_info.rssi != BluetoothDevice::kUnknownPower) { |
208 connection_info.transmit_power != BluetoothDevice::kUnknownPower && | |
209 connection_info.max_transmit_power != BluetoothDevice::kUnknownPower) { | |
210 AddSample(connection_info); | 159 AddSample(connection_info); |
211 } else { | 160 } else { |
212 PA_LOG(WARNING) << "[Proximity] Unkown values received from API: " | 161 PA_LOG(WARNING) << "[Proximity] Unkown values received from API: " |
213 << connection_info.rssi << " " | 162 << connection_info.rssi; |
214 << connection_info.transmit_power << " " | |
215 << connection_info.max_transmit_power; | |
216 rssi_rolling_average_.reset(); | 163 rssi_rolling_average_.reset(); |
217 last_transmit_power_reading_.reset(); | |
218 CheckForProximityStateChange(); | 164 CheckForProximityStateChange(); |
219 } | 165 } |
220 } | 166 } |
221 | 167 |
222 void ProximityMonitorImpl::ClearProximityState() { | 168 void ProximityMonitorImpl::ClearProximityState() { |
223 if (is_active_ && remote_device_is_in_proximity_) { | 169 if (is_active_ && remote_device_is_in_proximity_) { |
224 for (auto& observer : observers_) | 170 for (auto& observer : observers_) |
225 observer.OnProximityStateChanged(); | 171 observer.OnProximityStateChanged(); |
226 } | 172 } |
227 | 173 |
228 remote_device_is_in_proximity_ = false; | 174 remote_device_is_in_proximity_ = false; |
229 rssi_rolling_average_.reset(); | 175 rssi_rolling_average_.reset(); |
230 last_transmit_power_reading_.reset(); | |
231 last_zero_rssi_timestamp_.reset(); | |
232 } | 176 } |
233 | 177 |
234 void ProximityMonitorImpl::AddSample( | 178 void ProximityMonitorImpl::AddSample( |
235 const BluetoothDevice::ConnectionInfo& connection_info) { | 179 const BluetoothDevice::ConnectionInfo& connection_info) { |
236 double weight = kRssiSampleWeight; | 180 double weight = kRssiSampleWeight; |
237 if (!rssi_rolling_average_) { | 181 if (!rssi_rolling_average_) { |
238 rssi_rolling_average_.reset(new double(connection_info.rssi)); | 182 rssi_rolling_average_.reset(new double(connection_info.rssi)); |
239 } else { | 183 } else { |
240 *rssi_rolling_average_ = | 184 *rssi_rolling_average_ = |
241 weight * connection_info.rssi + (1 - weight) * (*rssi_rolling_average_); | 185 weight * connection_info.rssi + (1 - weight) * (*rssi_rolling_average_); |
242 } | 186 } |
243 last_transmit_power_reading_.reset(new TransmitPowerReading( | |
244 connection_info.transmit_power, connection_info.max_transmit_power)); | |
245 | |
246 // It's rare but possible for the RSSI to be positive briefly. | |
247 if (connection_info.rssi >= 0) | |
248 last_zero_rssi_timestamp_.reset(new base::TimeTicks(clock_->NowTicks())); | |
249 | 187 |
250 CheckForProximityStateChange(); | 188 CheckForProximityStateChange(); |
251 } | 189 } |
252 | 190 |
253 void ProximityMonitorImpl::CheckForProximityStateChange() { | 191 void ProximityMonitorImpl::CheckForProximityStateChange() { |
254 if (strategy_ == Strategy::NONE) | 192 bool is_now_in_proximity = |
255 return; | 193 rssi_rolling_average_ && *rssi_rolling_average_ > kRssiThreshold; |
256 | 194 |
257 bool is_now_in_proximity = false; | 195 if (rssi_rolling_average_) { |
258 switch (strategy_) { | 196 LOG(WARNING) << "RSSI: " << *rssi_rolling_average_; |
259 case Strategy::NONE: | |
260 return; | |
261 | |
262 case Strategy::CHECK_RSSI: | |
263 is_now_in_proximity = IsInRssiRange(); | |
264 break; | |
265 | |
266 case Strategy::CHECK_TRANSMIT_POWER: | |
267 is_now_in_proximity = (last_transmit_power_reading_ && | |
268 last_transmit_power_reading_->IsInProximity()); | |
269 break; | |
270 } | 197 } |
271 | 198 |
272 if (remote_device_is_in_proximity_ != is_now_in_proximity) { | 199 if (remote_device_is_in_proximity_ != is_now_in_proximity) { |
273 PA_LOG(INFO) << "[Proximity] Updated proximity state: " | 200 PA_LOG(INFO) << "[Proximity] Updated proximity state: " |
274 << (is_now_in_proximity ? "proximate" : "distant"); | 201 << (is_now_in_proximity ? "proximate" : "distant"); |
275 remote_device_is_in_proximity_ = is_now_in_proximity; | 202 remote_device_is_in_proximity_ = is_now_in_proximity; |
276 for (auto& observer : observers_) | 203 for (auto& observer : observers_) |
277 observer.OnProximityStateChanged(); | 204 observer.OnProximityStateChanged(); |
278 } | 205 } |
279 } | 206 } |
280 | 207 |
281 } // namespace proximity_auth | 208 } // namespace proximity_auth |
OLD | NEW |