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.
5 #include "components/proximity_auth/proximity_monitor_impl.h"
7 #include "base/macros.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/test/histogram_tester.h"
12 #include "base/test/simple_test_tick_clock.h"
13 #include "base/test/test_simple_task_runner.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h"
16 #include "components/proximity_auth/logging/logging.h"
17 #include "components/proximity_auth/proximity_monitor_observer.h"
18 #include "components/proximity_auth/remote_device.h"
19 #include "device/bluetooth/bluetooth_adapter_factory.h"
20 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using device::BluetoothDevice
;
26 using testing::NiceMock
;
27 using testing::Return
;
28 using testing::SaveArg
;
30 namespace proximity_auth
{
33 const char kBluetoothAddress
[] = "AA:BB:CC:DD:EE:FF";
34 const char kRemoteDeviceName
[] = "LGE Nexus 5";
36 class TestProximityMonitorImpl
: public ProximityMonitorImpl
{
38 explicit TestProximityMonitorImpl(const RemoteDevice
& remote_device
,
39 scoped_ptr
<base::TickClock
> clock
,
40 ProximityMonitorObserver
* observer
)
41 : ProximityMonitorImpl(remote_device
, clock
.Pass(), observer
) {}
42 ~TestProximityMonitorImpl() override
{}
44 using ProximityMonitorImpl::SetStrategy
;
47 DISALLOW_COPY_AND_ASSIGN(TestProximityMonitorImpl
);
50 class MockProximityMonitorObserver
: public ProximityMonitorObserver
{
52 MockProximityMonitorObserver() {}
53 ~MockProximityMonitorObserver() override
{}
55 MOCK_METHOD0(OnProximityStateChanged
, void());
58 DISALLOW_COPY_AND_ASSIGN(MockProximityMonitorObserver
);
61 // Creates a mock Bluetooth adapter and sets it as the global adapter for
63 scoped_refptr
<device::MockBluetoothAdapter
>
64 CreateAndRegisterMockBluetoothAdapter() {
65 scoped_refptr
<device::MockBluetoothAdapter
> adapter
=
66 new NiceMock
<device::MockBluetoothAdapter
>();
67 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter
);
73 class ProximityAuthProximityMonitorImplTest
: public testing::Test
{
75 ProximityAuthProximityMonitorImplTest()
76 : clock_(new base::SimpleTestTickClock()),
77 bluetooth_adapter_(CreateAndRegisterMockBluetoothAdapter()),
78 remote_bluetooth_device_(&*bluetooth_adapter_
,
83 true /* connected */),
84 monitor_({kRemoteDeviceName
, kBluetoothAddress
},
85 make_scoped_ptr(clock_
),
87 task_runner_(new base::TestSimpleTaskRunner()),
88 thread_task_runner_handle_(task_runner_
) {
89 ON_CALL(*bluetooth_adapter_
, GetDevice(kBluetoothAddress
))
90 .WillByDefault(Return(&remote_bluetooth_device_
));
91 ON_CALL(remote_bluetooth_device_
, GetConnectionInfo(_
))
92 .WillByDefault(SaveArg
<0>(&connection_info_callback_
));
94 ~ProximityAuthProximityMonitorImplTest() override
{}
96 void RunPendingTasks() { task_runner_
->RunPendingTasks(); }
98 void ProvideConnectionInfo(
99 const BluetoothDevice::ConnectionInfo
& connection_info
) {
101 connection_info_callback_
.Run(connection_info
);
103 // Reset the callback to ensure that tests correctly only respond at most
104 // once per call to GetConnectionInfo().
105 connection_info_callback_
= BluetoothDevice::ConnectionInfoCallback();
109 // Mock for verifying interactions with the proximity monitor's observer.
110 NiceMock
<MockProximityMonitorObserver
> observer_
;
112 // Clock used for verifying time calculations. Owned by the monitor_.
113 base::SimpleTestTickClock
* clock_
;
115 // Mocks used for verifying interactions with the Bluetooth subsystem.
116 scoped_refptr
<device::MockBluetoothAdapter
> bluetooth_adapter_
;
117 NiceMock
<device::MockBluetoothDevice
> remote_bluetooth_device_
;
119 // The proximity monitor under test.
120 TestProximityMonitorImpl monitor_
;
123 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
124 base::ThreadTaskRunnerHandle thread_task_runner_handle_
;
125 BluetoothDevice::ConnectionInfoCallback connection_info_callback_
;
126 ScopedDisableLoggingForTesting disable_logging_
;
129 TEST_F(ProximityAuthProximityMonitorImplTest
, GetStrategy
) {
130 EXPECT_EQ(ProximityMonitor::Strategy::NONE
, monitor_
.GetStrategy());
132 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
133 EXPECT_EQ(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
,
134 monitor_
.GetStrategy());
137 TEST_F(ProximityAuthProximityMonitorImplTest
, ProximityState_StrategyIsNone
) {
138 monitor_
.SetStrategy(ProximityMonitor::Strategy::NONE
);
140 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
141 EXPECT_FALSE(monitor_
.IsInRssiRange());
144 TEST_F(ProximityAuthProximityMonitorImplTest
, ProximityState_NeverStarted
) {
145 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
147 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
148 EXPECT_FALSE(monitor_
.IsInRssiRange());
151 TEST_F(ProximityAuthProximityMonitorImplTest
,
152 ProximityState_Started_NoConnectionInfoReceivedYet
) {
153 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
156 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
157 EXPECT_FALSE(monitor_
.IsInRssiRange());
160 TEST_F(ProximityAuthProximityMonitorImplTest
,
161 ProximityState_InformsObserverOfChanges
) {
162 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
164 // Initially, the device is not in proximity.
166 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
168 // Simulate a reading indicating proximity.
169 EXPECT_CALL(observer_
, OnProximityStateChanged()).Times(1);
170 ProvideConnectionInfo({0, 0, 4});
171 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
173 // Simulate a reading indicating non-proximity.
174 EXPECT_CALL(observer_
, OnProximityStateChanged()).Times(1);
175 ProvideConnectionInfo({0, 4, 4});
176 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
179 TEST_F(ProximityAuthProximityMonitorImplTest
,
180 ProximityState_CheckRssi_RssiIndicatesProximity_TxPowerDoesNot
) {
181 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
184 ProvideConnectionInfo({0, 4, 4});
186 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
187 EXPECT_TRUE(monitor_
.IsInRssiRange());
190 TEST_F(ProximityAuthProximityMonitorImplTest
,
191 ProximityState_CheckRssi_TxPowerIndicatesProximity_RssiDoesNot
) {
192 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
195 ProvideConnectionInfo({-10, 0, 4});
197 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
198 EXPECT_FALSE(monitor_
.IsInRssiRange());
201 TEST_F(ProximityAuthProximityMonitorImplTest
,
202 ProximityState_CheckRssi_NeitherRssiNorTxPowerIndicatesProximity
) {
203 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
206 ProvideConnectionInfo({-10, 4, 4});
208 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
209 EXPECT_FALSE(monitor_
.IsInRssiRange());
212 TEST_F(ProximityAuthProximityMonitorImplTest
,
213 ProximityState_CheckRssi_BothRssiAndTxPowerIndicateProximity
) {
214 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
217 ProvideConnectionInfo({0, 0, 4});
219 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
220 EXPECT_TRUE(monitor_
.IsInRssiRange());
223 TEST_F(ProximityAuthProximityMonitorImplTest
,
224 ProximityState_CheckRssi_UnknownRssi
) {
225 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
228 ProvideConnectionInfo({0, 0, 4});
229 ProvideConnectionInfo({BluetoothDevice::kUnknownPower
, 0, 4});
231 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
232 EXPECT_FALSE(monitor_
.IsInRssiRange());
235 TEST_F(ProximityAuthProximityMonitorImplTest
,
236 ProximityState_CheckRssi_UnknownTxPower
) {
237 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
240 ProvideConnectionInfo({0, 0, 4});
241 ProvideConnectionInfo({0, BluetoothDevice::kUnknownPower
, 4});
243 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
244 EXPECT_FALSE(monitor_
.IsInRssiRange());
247 TEST_F(ProximityAuthProximityMonitorImplTest
,
248 ProximityState_CheckRssi_UnknownMaxTxPower
) {
249 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
252 ProvideConnectionInfo({0, 0, 4});
253 ProvideConnectionInfo({0, 0, BluetoothDevice::kUnknownPower
});
255 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
256 EXPECT_FALSE(monitor_
.IsInRssiRange());
259 TEST_F(ProximityAuthProximityMonitorImplTest
,
260 ProximityState_CheckTxPower_RssiIndicatesProximity_TxPowerDoesNot
) {
261 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
264 ProvideConnectionInfo({0, 4, 4});
266 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
267 EXPECT_TRUE(monitor_
.IsInRssiRange());
270 TEST_F(ProximityAuthProximityMonitorImplTest
,
271 ProximityState_CheckTxPower_TxPowerIndicatesProximity_RssiDoesNot
) {
272 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
275 ProvideConnectionInfo({-10, 0, 4});
277 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
278 EXPECT_FALSE(monitor_
.IsInRssiRange());
281 TEST_F(ProximityAuthProximityMonitorImplTest
,
282 ProximityState_CheckTxPower_NeitherRssiNorTxPowerIndicatesProximity
) {
283 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
286 ProvideConnectionInfo({-10, 4, 4});
288 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
289 EXPECT_FALSE(monitor_
.IsInRssiRange());
292 TEST_F(ProximityAuthProximityMonitorImplTest
,
293 ProximityState_CheckTxPower_BothRssiAndTxPowerIndicateProximity
) {
294 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
297 ProvideConnectionInfo({0, 0, 4});
299 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
300 EXPECT_TRUE(monitor_
.IsInRssiRange());
303 TEST_F(ProximityAuthProximityMonitorImplTest
,
304 ProximityState_CheckTxPower_UnknownRssi
) {
305 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
308 ProvideConnectionInfo({0, 0, 4});
309 ProvideConnectionInfo({BluetoothDevice::kUnknownPower
, 0, 4});
311 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
312 EXPECT_FALSE(monitor_
.IsInRssiRange());
315 TEST_F(ProximityAuthProximityMonitorImplTest
,
316 ProximityState_CheckTxPower_UnknownTxPower
) {
317 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
320 ProvideConnectionInfo({0, 0, 4});
321 ProvideConnectionInfo({0, BluetoothDevice::kUnknownPower
, 4});
323 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
324 EXPECT_FALSE(monitor_
.IsInRssiRange());
327 TEST_F(ProximityAuthProximityMonitorImplTest
,
328 ProximityState_CheckTxPower_UnknownMaxTxPower
) {
329 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
332 ProvideConnectionInfo({0, 0, 4});
333 ProvideConnectionInfo({0, 0, BluetoothDevice::kUnknownPower
});
335 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
336 EXPECT_FALSE(monitor_
.IsInRssiRange());
339 TEST_F(ProximityAuthProximityMonitorImplTest
, ProximityState_StartThenStop
) {
340 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
343 ProvideConnectionInfo({0, 0, 4});
346 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
347 EXPECT_FALSE(monitor_
.IsInRssiRange());
350 TEST_F(ProximityAuthProximityMonitorImplTest
,
351 ProximityState_StartThenStopThenStartAgain
) {
352 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
355 ProvideConnectionInfo({-10, 4, 4});
356 ProvideConnectionInfo({-10, 4, 4});
357 ProvideConnectionInfo({-10, 4, 4});
358 ProvideConnectionInfo({-10, 4, 4});
359 ProvideConnectionInfo({-10, 4, 4});
362 // Restarting the monitor should immediately reset the proximity state, rather
363 // than building on the previous rolling average.
365 ProvideConnectionInfo({0, 4, 4});
367 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
368 EXPECT_TRUE(monitor_
.IsInRssiRange());
371 TEST_F(ProximityAuthProximityMonitorImplTest
,
372 ProximityState_RemoteDeviceRemainsInProximity
) {
373 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
376 ProvideConnectionInfo({0, 4, 4});
377 ProvideConnectionInfo({-1, 4, 4});
378 ProvideConnectionInfo({0, 4, 4});
379 ProvideConnectionInfo({-2, 4, 4});
380 ProvideConnectionInfo({-1, 4, 4});
382 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
383 EXPECT_TRUE(monitor_
.IsInRssiRange());
385 // Brief drops in RSSI should be handled by weighted averaging.
386 ProvideConnectionInfo({-10, 4, 4});
388 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
389 EXPECT_TRUE(monitor_
.IsInRssiRange());
392 TEST_F(ProximityAuthProximityMonitorImplTest
,
393 ProximityState_RemoteDeviceLeavesProximity
) {
394 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
397 // Start with a device in proximity.
398 ProvideConnectionInfo({0, 4, 4});
399 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
400 EXPECT_TRUE(monitor_
.IsInRssiRange());
402 // Simulate readings for the remote device leaving proximity.
403 ProvideConnectionInfo({-1, 4, 4});
404 ProvideConnectionInfo({-4, 4, 4});
405 ProvideConnectionInfo({0, 4, 4});
406 ProvideConnectionInfo({-10, 4, 4});
407 ProvideConnectionInfo({-8, 4, 4});
408 ProvideConnectionInfo({-15, 4, 4});
409 ProvideConnectionInfo({-10, 4, 4});
410 ProvideConnectionInfo({-10, 4, 4});
411 ProvideConnectionInfo({-10, 4, 4});
412 ProvideConnectionInfo({-10, 4, 4});
414 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
415 EXPECT_FALSE(monitor_
.IsInRssiRange());
418 TEST_F(ProximityAuthProximityMonitorImplTest
,
419 ProximityState_RemoteDeviceEntersProximity
) {
420 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
423 // Start with a device in proximity.
424 ProvideConnectionInfo({-20, 4, 4});
425 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
426 EXPECT_FALSE(monitor_
.IsInRssiRange());
428 // Simulate readings for the remote device entering proximity.
429 ProvideConnectionInfo({-15, 4, 4});
430 ProvideConnectionInfo({-8, 4, 4});
431 ProvideConnectionInfo({-12, 4, 4});
432 ProvideConnectionInfo({-18, 4, 4});
433 ProvideConnectionInfo({-7, 4, 4});
434 ProvideConnectionInfo({-3, 4, 4});
435 ProvideConnectionInfo({-2, 4, 4});
436 ProvideConnectionInfo({0, 4, 4});
437 ProvideConnectionInfo({0, 4, 4});
439 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
440 EXPECT_TRUE(monitor_
.IsInRssiRange());
443 TEST_F(ProximityAuthProximityMonitorImplTest
,
444 ProximityState_DeviceNotKnownToAdapter
) {
445 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
448 // Start with the device known to the adapter and in proximity.
449 ProvideConnectionInfo({0, 4, 4});
450 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
451 EXPECT_TRUE(monitor_
.IsInRssiRange());
453 // Simulate it being forgotten.
454 ON_CALL(*bluetooth_adapter_
, GetDevice(kBluetoothAddress
))
455 .WillByDefault(Return(nullptr));
456 EXPECT_CALL(observer_
, OnProximityStateChanged());
459 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
460 EXPECT_FALSE(monitor_
.IsInRssiRange());
463 TEST_F(ProximityAuthProximityMonitorImplTest
,
464 ProximityState_DeviceNotConnected
) {
465 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
468 // Start with the device connected and in proximity.
469 ProvideConnectionInfo({0, 4, 4});
470 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
471 EXPECT_TRUE(monitor_
.IsInRssiRange());
473 // Simulate it disconnecting.
474 ON_CALL(remote_bluetooth_device_
, IsConnected()).WillByDefault(Return(false));
475 EXPECT_CALL(observer_
, OnProximityStateChanged());
478 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
479 EXPECT_FALSE(monitor_
.IsInRssiRange());
482 TEST_F(ProximityAuthProximityMonitorImplTest
,
483 ProximityState_ConnectionInfoReceivedAfterStopping
) {
484 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
488 ProvideConnectionInfo({0, 4, 4});
490 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
491 EXPECT_FALSE(monitor_
.IsInRssiRange());
494 TEST_F(ProximityAuthProximityMonitorImplTest
,
495 RecordProximityMetricsOnAuthSuccess_NormalValues
) {
497 ProvideConnectionInfo({0, 0, 4});
499 clock_
->Advance(base::TimeDelta::FromMilliseconds(101));
500 ProvideConnectionInfo({-20, 3, 4});
502 clock_
->Advance(base::TimeDelta::FromMilliseconds(203));
503 base::HistogramTester histogram_tester
;
504 monitor_
.RecordProximityMetricsOnAuthSuccess();
505 histogram_tester
.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi",
507 histogram_tester
.ExpectUniqueSample(
508 "EasyUnlock.AuthProximity.TransmitPowerDelta", -1, 1);
509 histogram_tester
.ExpectUniqueSample(
510 "EasyUnlock.AuthProximity.TimeSinceLastZeroRssi", 304, 1);
511 histogram_tester
.ExpectUniqueSample(
512 "EasyUnlock.AuthProximity.RemoteDeviceModelHash",
513 1881443083 /* hash of "LGE Nexus 5" */, 1);
516 TEST_F(ProximityAuthProximityMonitorImplTest
,
517 RecordProximityMetricsOnAuthSuccess_ClampedValues
) {
519 ProvideConnectionInfo({-99999, 99999, 12345});
521 base::HistogramTester histogram_tester
;
522 monitor_
.RecordProximityMetricsOnAuthSuccess();
523 histogram_tester
.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi",
525 histogram_tester
.ExpectUniqueSample(
526 "EasyUnlock.AuthProximity.TransmitPowerDelta", 50, 1);
529 TEST_F(ProximityAuthProximityMonitorImplTest
,
530 RecordProximityMetricsOnAuthSuccess_UnknownValues
) {
531 RemoteDevice unnamed_remote_device
= {kBluetoothAddress
, kBluetoothAddress
};
532 scoped_ptr
<base::TickClock
> clock(new base::SimpleTestTickClock());
533 ProximityMonitorImpl
monitor(unnamed_remote_device
, clock
.Pass(), &observer_
);
535 ProvideConnectionInfo({127, 127, 127});
537 base::HistogramTester histogram_tester
;
538 monitor
.RecordProximityMetricsOnAuthSuccess();
539 histogram_tester
.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi",
541 histogram_tester
.ExpectUniqueSample(
542 "EasyUnlock.AuthProximity.TransmitPowerDelta", 127, 1);
543 histogram_tester
.ExpectUniqueSample(
544 "EasyUnlock.AuthProximity.TimeSinceLastZeroRssi",
545 base::TimeDelta::FromSeconds(10).InMilliseconds(), 1);
546 histogram_tester
.ExpectUniqueSample(
547 "EasyUnlock.AuthProximity.RemoteDeviceModelHash",
548 -1808066424 /* hash of "Unknown" */, 1);
551 } // namespace proximity_auth