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/test/histogram_tester.h"
11 #include "base/test/simple_test_tick_clock.h"
12 #include "base/test/test_simple_task_runner.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "components/proximity_auth/logging/logging.h"
16 #include "components/proximity_auth/proximity_monitor_observer.h"
17 #include "components/proximity_auth/remote_device.h"
18 #include "device/bluetooth/bluetooth_adapter_factory.h"
19 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using device::BluetoothDevice
;
25 using testing::NiceMock
;
26 using testing::Return
;
27 using testing::SaveArg
;
29 namespace proximity_auth
{
32 const char kBluetoothAddress
[] = "AA:BB:CC:DD:EE:FF";
33 const char kRemoteDevicePublicKey
[] = "Remote Public Key";
34 const char kRemoteDeviceName
[] = "LGE Nexus 5";
35 const char kPersistentSymmetricKey
[] = "PSK";
37 class TestProximityMonitorImpl
: public ProximityMonitorImpl
{
39 explicit TestProximityMonitorImpl(const RemoteDevice
& remote_device
,
40 scoped_ptr
<base::TickClock
> clock
,
41 ProximityMonitorObserver
* observer
)
42 : ProximityMonitorImpl(remote_device
, clock
.Pass(), observer
) {}
43 ~TestProximityMonitorImpl() override
{}
45 using ProximityMonitorImpl::SetStrategy
;
48 DISALLOW_COPY_AND_ASSIGN(TestProximityMonitorImpl
);
51 class MockProximityMonitorObserver
: public ProximityMonitorObserver
{
53 MockProximityMonitorObserver() {}
54 ~MockProximityMonitorObserver() override
{}
56 MOCK_METHOD0(OnProximityStateChanged
, void());
59 DISALLOW_COPY_AND_ASSIGN(MockProximityMonitorObserver
);
62 // Creates a mock Bluetooth adapter and sets it as the global adapter for
64 scoped_refptr
<device::MockBluetoothAdapter
>
65 CreateAndRegisterMockBluetoothAdapter() {
66 scoped_refptr
<device::MockBluetoothAdapter
> adapter
=
67 new NiceMock
<device::MockBluetoothAdapter
>();
68 device::BluetoothAdapterFactory::SetAdapterForTesting(adapter
);
74 class ProximityAuthProximityMonitorImplTest
: public testing::Test
{
76 ProximityAuthProximityMonitorImplTest()
77 : clock_(new base::SimpleTestTickClock()),
78 bluetooth_adapter_(CreateAndRegisterMockBluetoothAdapter()),
79 remote_bluetooth_device_(&*bluetooth_adapter_
,
84 true /* connected */),
85 monitor_(RemoteDevice(kRemoteDeviceName
,
86 kRemoteDevicePublicKey
,
88 kPersistentSymmetricKey
),
89 make_scoped_ptr(clock_
),
91 task_runner_(new base::TestSimpleTaskRunner()),
92 thread_task_runner_handle_(task_runner_
) {
93 ON_CALL(*bluetooth_adapter_
, GetDevice(kBluetoothAddress
))
94 .WillByDefault(Return(&remote_bluetooth_device_
));
95 ON_CALL(remote_bluetooth_device_
, GetConnectionInfo(_
))
96 .WillByDefault(SaveArg
<0>(&connection_info_callback_
));
98 ~ProximityAuthProximityMonitorImplTest() override
{}
100 void RunPendingTasks() { task_runner_
->RunPendingTasks(); }
102 void ProvideConnectionInfo(
103 const BluetoothDevice::ConnectionInfo
& connection_info
) {
105 connection_info_callback_
.Run(connection_info
);
107 // Reset the callback to ensure that tests correctly only respond at most
108 // once per call to GetConnectionInfo().
109 connection_info_callback_
= BluetoothDevice::ConnectionInfoCallback();
113 // Mock for verifying interactions with the proximity monitor's observer.
114 NiceMock
<MockProximityMonitorObserver
> observer_
;
116 // Clock used for verifying time calculations. Owned by the monitor_.
117 base::SimpleTestTickClock
* clock_
;
119 // Mocks used for verifying interactions with the Bluetooth subsystem.
120 scoped_refptr
<device::MockBluetoothAdapter
> bluetooth_adapter_
;
121 NiceMock
<device::MockBluetoothDevice
> remote_bluetooth_device_
;
123 // The proximity monitor under test.
124 TestProximityMonitorImpl monitor_
;
127 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
128 base::ThreadTaskRunnerHandle thread_task_runner_handle_
;
129 BluetoothDevice::ConnectionInfoCallback connection_info_callback_
;
130 ScopedDisableLoggingForTesting disable_logging_
;
133 TEST_F(ProximityAuthProximityMonitorImplTest
, GetStrategy
) {
134 EXPECT_EQ(ProximityMonitor::Strategy::NONE
, monitor_
.GetStrategy());
136 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
137 EXPECT_EQ(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
,
138 monitor_
.GetStrategy());
141 TEST_F(ProximityAuthProximityMonitorImplTest
, ProximityState_StrategyIsNone
) {
142 monitor_
.SetStrategy(ProximityMonitor::Strategy::NONE
);
144 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
145 EXPECT_FALSE(monitor_
.IsInRssiRange());
148 TEST_F(ProximityAuthProximityMonitorImplTest
, ProximityState_NeverStarted
) {
149 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
151 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
152 EXPECT_FALSE(monitor_
.IsInRssiRange());
155 TEST_F(ProximityAuthProximityMonitorImplTest
,
156 ProximityState_Started_NoConnectionInfoReceivedYet
) {
157 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
160 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
161 EXPECT_FALSE(monitor_
.IsInRssiRange());
164 TEST_F(ProximityAuthProximityMonitorImplTest
,
165 ProximityState_InformsObserverOfChanges
) {
166 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
168 // Initially, the device is not in proximity.
170 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
172 // Simulate a reading indicating proximity.
173 EXPECT_CALL(observer_
, OnProximityStateChanged()).Times(1);
174 ProvideConnectionInfo({0, 0, 4});
175 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
177 // Simulate a reading indicating non-proximity.
178 EXPECT_CALL(observer_
, OnProximityStateChanged()).Times(1);
179 ProvideConnectionInfo({0, 4, 4});
180 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
183 TEST_F(ProximityAuthProximityMonitorImplTest
,
184 ProximityState_CheckRssi_RssiIndicatesProximity_TxPowerDoesNot
) {
185 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
188 ProvideConnectionInfo({0, 4, 4});
190 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
191 EXPECT_TRUE(monitor_
.IsInRssiRange());
194 TEST_F(ProximityAuthProximityMonitorImplTest
,
195 ProximityState_CheckRssi_TxPowerIndicatesProximity_RssiDoesNot
) {
196 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
199 ProvideConnectionInfo({-10, 0, 4});
201 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
202 EXPECT_FALSE(monitor_
.IsInRssiRange());
205 TEST_F(ProximityAuthProximityMonitorImplTest
,
206 ProximityState_CheckRssi_NeitherRssiNorTxPowerIndicatesProximity
) {
207 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
210 ProvideConnectionInfo({-10, 4, 4});
212 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
213 EXPECT_FALSE(monitor_
.IsInRssiRange());
216 TEST_F(ProximityAuthProximityMonitorImplTest
,
217 ProximityState_CheckRssi_BothRssiAndTxPowerIndicateProximity
) {
218 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
221 ProvideConnectionInfo({0, 0, 4});
223 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
224 EXPECT_TRUE(monitor_
.IsInRssiRange());
227 TEST_F(ProximityAuthProximityMonitorImplTest
,
228 ProximityState_CheckRssi_UnknownRssi
) {
229 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
232 ProvideConnectionInfo({0, 0, 4});
233 ProvideConnectionInfo({BluetoothDevice::kUnknownPower
, 0, 4});
235 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
236 EXPECT_FALSE(monitor_
.IsInRssiRange());
239 TEST_F(ProximityAuthProximityMonitorImplTest
,
240 ProximityState_CheckRssi_UnknownTxPower
) {
241 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
244 ProvideConnectionInfo({0, 0, 4});
245 ProvideConnectionInfo({0, BluetoothDevice::kUnknownPower
, 4});
247 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
248 EXPECT_FALSE(monitor_
.IsInRssiRange());
251 TEST_F(ProximityAuthProximityMonitorImplTest
,
252 ProximityState_CheckRssi_UnknownMaxTxPower
) {
253 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
256 ProvideConnectionInfo({0, 0, 4});
257 ProvideConnectionInfo({0, 0, BluetoothDevice::kUnknownPower
});
259 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
260 EXPECT_FALSE(monitor_
.IsInRssiRange());
263 TEST_F(ProximityAuthProximityMonitorImplTest
,
264 ProximityState_CheckTxPower_RssiIndicatesProximity_TxPowerDoesNot
) {
265 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
268 ProvideConnectionInfo({0, 4, 4});
270 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
271 EXPECT_TRUE(monitor_
.IsInRssiRange());
274 TEST_F(ProximityAuthProximityMonitorImplTest
,
275 ProximityState_CheckTxPower_TxPowerIndicatesProximity_RssiDoesNot
) {
276 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
279 ProvideConnectionInfo({-10, 0, 4});
281 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
282 EXPECT_FALSE(monitor_
.IsInRssiRange());
285 TEST_F(ProximityAuthProximityMonitorImplTest
,
286 ProximityState_CheckTxPower_NeitherRssiNorTxPowerIndicatesProximity
) {
287 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
290 ProvideConnectionInfo({-10, 4, 4});
292 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
293 EXPECT_FALSE(monitor_
.IsInRssiRange());
296 TEST_F(ProximityAuthProximityMonitorImplTest
,
297 ProximityState_CheckTxPower_BothRssiAndTxPowerIndicateProximity
) {
298 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
301 ProvideConnectionInfo({0, 0, 4});
303 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
304 EXPECT_TRUE(monitor_
.IsInRssiRange());
307 TEST_F(ProximityAuthProximityMonitorImplTest
,
308 ProximityState_CheckTxPower_UnknownRssi
) {
309 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
312 ProvideConnectionInfo({0, 0, 4});
313 ProvideConnectionInfo({BluetoothDevice::kUnknownPower
, 0, 4});
315 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
316 EXPECT_FALSE(monitor_
.IsInRssiRange());
319 TEST_F(ProximityAuthProximityMonitorImplTest
,
320 ProximityState_CheckTxPower_UnknownTxPower
) {
321 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
324 ProvideConnectionInfo({0, 0, 4});
325 ProvideConnectionInfo({0, BluetoothDevice::kUnknownPower
, 4});
327 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
328 EXPECT_FALSE(monitor_
.IsInRssiRange());
331 TEST_F(ProximityAuthProximityMonitorImplTest
,
332 ProximityState_CheckTxPower_UnknownMaxTxPower
) {
333 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_TRANSMIT_POWER
);
336 ProvideConnectionInfo({0, 0, 4});
337 ProvideConnectionInfo({0, 0, BluetoothDevice::kUnknownPower
});
339 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
340 EXPECT_FALSE(monitor_
.IsInRssiRange());
343 TEST_F(ProximityAuthProximityMonitorImplTest
, ProximityState_StartThenStop
) {
344 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
347 ProvideConnectionInfo({0, 0, 4});
350 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
351 EXPECT_FALSE(monitor_
.IsInRssiRange());
354 TEST_F(ProximityAuthProximityMonitorImplTest
,
355 ProximityState_StartThenStopThenStartAgain
) {
356 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
359 ProvideConnectionInfo({-10, 4, 4});
360 ProvideConnectionInfo({-10, 4, 4});
361 ProvideConnectionInfo({-10, 4, 4});
362 ProvideConnectionInfo({-10, 4, 4});
363 ProvideConnectionInfo({-10, 4, 4});
366 // Restarting the monitor should immediately reset the proximity state, rather
367 // than building on the previous rolling average.
369 ProvideConnectionInfo({0, 4, 4});
371 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
372 EXPECT_TRUE(monitor_
.IsInRssiRange());
375 TEST_F(ProximityAuthProximityMonitorImplTest
,
376 ProximityState_RemoteDeviceRemainsInProximity
) {
377 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
380 ProvideConnectionInfo({0, 4, 4});
381 ProvideConnectionInfo({-1, 4, 4});
382 ProvideConnectionInfo({0, 4, 4});
383 ProvideConnectionInfo({-2, 4, 4});
384 ProvideConnectionInfo({-1, 4, 4});
386 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
387 EXPECT_TRUE(monitor_
.IsInRssiRange());
389 // Brief drops in RSSI should be handled by weighted averaging.
390 ProvideConnectionInfo({-10, 4, 4});
392 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
393 EXPECT_TRUE(monitor_
.IsInRssiRange());
396 TEST_F(ProximityAuthProximityMonitorImplTest
,
397 ProximityState_RemoteDeviceLeavesProximity
) {
398 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
401 // Start with a device in proximity.
402 ProvideConnectionInfo({0, 4, 4});
403 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
404 EXPECT_TRUE(monitor_
.IsInRssiRange());
406 // Simulate readings for the remote device leaving proximity.
407 ProvideConnectionInfo({-1, 4, 4});
408 ProvideConnectionInfo({-4, 4, 4});
409 ProvideConnectionInfo({0, 4, 4});
410 ProvideConnectionInfo({-10, 4, 4});
411 ProvideConnectionInfo({-8, 4, 4});
412 ProvideConnectionInfo({-15, 4, 4});
413 ProvideConnectionInfo({-10, 4, 4});
414 ProvideConnectionInfo({-10, 4, 4});
415 ProvideConnectionInfo({-10, 4, 4});
416 ProvideConnectionInfo({-10, 4, 4});
418 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
419 EXPECT_FALSE(monitor_
.IsInRssiRange());
422 TEST_F(ProximityAuthProximityMonitorImplTest
,
423 ProximityState_RemoteDeviceEntersProximity
) {
424 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
427 // Start with a device in proximity.
428 ProvideConnectionInfo({-20, 4, 4});
429 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
430 EXPECT_FALSE(monitor_
.IsInRssiRange());
432 // Simulate readings for the remote device entering proximity.
433 ProvideConnectionInfo({-15, 4, 4});
434 ProvideConnectionInfo({-8, 4, 4});
435 ProvideConnectionInfo({-12, 4, 4});
436 ProvideConnectionInfo({-18, 4, 4});
437 ProvideConnectionInfo({-7, 4, 4});
438 ProvideConnectionInfo({-3, 4, 4});
439 ProvideConnectionInfo({-2, 4, 4});
440 ProvideConnectionInfo({0, 4, 4});
441 ProvideConnectionInfo({0, 4, 4});
443 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
444 EXPECT_TRUE(monitor_
.IsInRssiRange());
447 TEST_F(ProximityAuthProximityMonitorImplTest
,
448 ProximityState_DeviceNotKnownToAdapter
) {
449 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
452 // Start with the device known to the adapter and in proximity.
453 ProvideConnectionInfo({0, 4, 4});
454 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
455 EXPECT_TRUE(monitor_
.IsInRssiRange());
457 // Simulate it being forgotten.
458 ON_CALL(*bluetooth_adapter_
, GetDevice(kBluetoothAddress
))
459 .WillByDefault(Return(nullptr));
460 EXPECT_CALL(observer_
, OnProximityStateChanged());
463 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
464 EXPECT_FALSE(monitor_
.IsInRssiRange());
467 TEST_F(ProximityAuthProximityMonitorImplTest
,
468 ProximityState_DeviceNotConnected
) {
469 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
472 // Start with the device connected and in proximity.
473 ProvideConnectionInfo({0, 4, 4});
474 EXPECT_TRUE(monitor_
.IsUnlockAllowed());
475 EXPECT_TRUE(monitor_
.IsInRssiRange());
477 // Simulate it disconnecting.
478 ON_CALL(remote_bluetooth_device_
, IsConnected()).WillByDefault(Return(false));
479 EXPECT_CALL(observer_
, OnProximityStateChanged());
482 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
483 EXPECT_FALSE(monitor_
.IsInRssiRange());
486 TEST_F(ProximityAuthProximityMonitorImplTest
,
487 ProximityState_ConnectionInfoReceivedAfterStopping
) {
488 monitor_
.SetStrategy(ProximityMonitor::Strategy::CHECK_RSSI
);
492 ProvideConnectionInfo({0, 4, 4});
494 EXPECT_FALSE(monitor_
.IsUnlockAllowed());
495 EXPECT_FALSE(monitor_
.IsInRssiRange());
498 TEST_F(ProximityAuthProximityMonitorImplTest
,
499 RecordProximityMetricsOnAuthSuccess_NormalValues
) {
501 ProvideConnectionInfo({0, 0, 4});
503 clock_
->Advance(base::TimeDelta::FromMilliseconds(101));
504 ProvideConnectionInfo({-20, 3, 4});
506 clock_
->Advance(base::TimeDelta::FromMilliseconds(203));
507 base::HistogramTester histogram_tester
;
508 monitor_
.RecordProximityMetricsOnAuthSuccess();
509 histogram_tester
.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi",
511 histogram_tester
.ExpectUniqueSample(
512 "EasyUnlock.AuthProximity.TransmitPowerDelta", -1, 1);
513 histogram_tester
.ExpectUniqueSample(
514 "EasyUnlock.AuthProximity.TimeSinceLastZeroRssi", 304, 1);
515 histogram_tester
.ExpectUniqueSample(
516 "EasyUnlock.AuthProximity.RemoteDeviceModelHash",
517 1881443083 /* hash of "LGE Nexus 5" */, 1);
520 TEST_F(ProximityAuthProximityMonitorImplTest
,
521 RecordProximityMetricsOnAuthSuccess_ClampedValues
) {
523 ProvideConnectionInfo({-99999, 99999, 12345});
525 base::HistogramTester histogram_tester
;
526 monitor_
.RecordProximityMetricsOnAuthSuccess();
527 histogram_tester
.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi",
529 histogram_tester
.ExpectUniqueSample(
530 "EasyUnlock.AuthProximity.TransmitPowerDelta", 50, 1);
533 TEST_F(ProximityAuthProximityMonitorImplTest
,
534 RecordProximityMetricsOnAuthSuccess_UnknownValues
) {
535 // Note: A device without a recorded name will have its Bluetooth address as
537 RemoteDevice
unnamed_remote_device(kBluetoothAddress
, kRemoteDevicePublicKey
,
539 kPersistentSymmetricKey
);
541 scoped_ptr
<base::TickClock
> clock(new base::SimpleTestTickClock());
542 ProximityMonitorImpl
monitor(unnamed_remote_device
, clock
.Pass(), &observer_
);
544 ProvideConnectionInfo({127, 127, 127});
546 base::HistogramTester histogram_tester
;
547 monitor
.RecordProximityMetricsOnAuthSuccess();
548 histogram_tester
.ExpectUniqueSample("EasyUnlock.AuthProximity.RollingRssi",
550 histogram_tester
.ExpectUniqueSample(
551 "EasyUnlock.AuthProximity.TransmitPowerDelta", 127, 1);
552 histogram_tester
.ExpectUniqueSample(
553 "EasyUnlock.AuthProximity.TimeSinceLastZeroRssi",
554 base::TimeDelta::FromSeconds(10).InMilliseconds(), 1);
555 histogram_tester
.ExpectUniqueSample(
556 "EasyUnlock.AuthProximity.RemoteDeviceModelHash",
557 -1808066424 /* hash of "Unknown" */, 1);
560 } // namespace proximity_auth