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/remote_device_life_cycle_impl.h"
8 #include "base/location.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/time/default_tick_clock.h"
11 #include "components/proximity_auth/ble/bluetooth_low_energy_connection.h"
12 #include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h"
13 #include "components/proximity_auth/bluetooth_connection.h"
14 #include "components/proximity_auth/bluetooth_connection_finder.h"
15 #include "components/proximity_auth/bluetooth_throttler_impl.h"
16 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
17 #include "components/proximity_auth/device_to_device_authenticator.h"
18 #include "components/proximity_auth/logging/logging.h"
19 #include "components/proximity_auth/messenger_impl.h"
20 #include "components/proximity_auth/proximity_auth_client.h"
21 #include "components/proximity_auth/secure_context.h"
23 namespace proximity_auth
{
27 // The UUID of the Smart Lock classic Bluetooth service.
28 const char kClassicBluetoothServiceUUID
[] =
29 "704EE561-3782-405A-A14B-2D47A2DDCDDF";
31 // The UUID of the Bluetooth Low Energy service.
32 const char kBLESmartLockServiceUUID
[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11";
34 // The time to wait, in seconds, after authentication fails, before retrying
35 // another connection.
36 const int kAuthenticationRecoveryTimeSeconds
= 10;
40 RemoteDeviceLifeCycleImpl::RemoteDeviceLifeCycleImpl(
41 const RemoteDevice
& remote_device
,
42 ProximityAuthClient
* proximity_auth_client
)
43 : remote_device_(remote_device
),
44 proximity_auth_client_(proximity_auth_client
),
45 state_(RemoteDeviceLifeCycle::State::STOPPED
),
46 bluetooth_throttler_(new BluetoothThrottlerImpl(
47 make_scoped_ptr(new base::DefaultTickClock()))),
48 weak_ptr_factory_(this) {}
50 RemoteDeviceLifeCycleImpl::~RemoteDeviceLifeCycleImpl() {}
52 void RemoteDeviceLifeCycleImpl::Start() {
53 PA_LOG(INFO
) << "Life cycle started.";
54 DCHECK(state_
== RemoteDeviceLifeCycle::State::STOPPED
);
58 RemoteDeviceLifeCycle::State
RemoteDeviceLifeCycleImpl::GetState() const {
62 Messenger
* RemoteDeviceLifeCycleImpl::GetMessenger() {
63 return messenger_
.get();
66 void RemoteDeviceLifeCycleImpl::AddObserver(Observer
* observer
) {
67 observers_
.AddObserver(observer
);
70 void RemoteDeviceLifeCycleImpl::RemoveObserver(Observer
* observer
) {
71 observers_
.RemoveObserver(observer
);
74 scoped_ptr
<ConnectionFinder
>
75 RemoteDeviceLifeCycleImpl::CreateConnectionFinder() {
76 // TODO(tengs): We should not rely on the assumption that an empty Bluetooth
77 // address means that the device is BLE.
78 if (remote_device_
.bluetooth_address
.empty()) {
79 return make_scoped_ptr(new BluetoothLowEnergyConnectionFinder(
80 remote_device_
, kBLESmartLockServiceUUID
,
81 BluetoothLowEnergyConnectionFinder::FinderStrategy::FIND_PAIRED_DEVICE
,
82 nullptr, bluetooth_throttler_
.get(), 3));
84 return make_scoped_ptr(new BluetoothConnectionFinder(
85 remote_device_
, device::BluetoothUUID(kClassicBluetoothServiceUUID
),
86 base::TimeDelta::FromSeconds(3)));
90 scoped_ptr
<Authenticator
> RemoteDeviceLifeCycleImpl::CreateAuthenticator() {
91 return make_scoped_ptr(new DeviceToDeviceAuthenticator(
92 connection_
.get(), proximity_auth_client_
->GetAccountId(),
93 proximity_auth_client_
->CreateSecureMessageDelegate()));
96 void RemoteDeviceLifeCycleImpl::TransitionToState(
97 RemoteDeviceLifeCycle::State new_state
) {
98 RemoteDeviceLifeCycle::State old_state
= state_
;
100 FOR_EACH_OBSERVER(Observer
, observers_
,
101 OnLifeCycleStateChanged(old_state
, new_state
));
104 void RemoteDeviceLifeCycleImpl::FindConnection() {
105 connection_finder_
= CreateConnectionFinder();
106 connection_finder_
->Find(
107 base::Bind(&RemoteDeviceLifeCycleImpl::OnConnectionFound
,
108 weak_ptr_factory_
.GetWeakPtr()));
109 TransitionToState(RemoteDeviceLifeCycle::State::FINDING_CONNECTION
);
112 void RemoteDeviceLifeCycleImpl::OnConnectionFound(
113 scoped_ptr
<Connection
> connection
) {
114 DCHECK(state_
== RemoteDeviceLifeCycle::State::FINDING_CONNECTION
);
115 connection_
= connection
.Pass();
116 authenticator_
= CreateAuthenticator();
117 authenticator_
->Authenticate(
118 base::Bind(&RemoteDeviceLifeCycleImpl::OnAuthenticationResult
,
119 weak_ptr_factory_
.GetWeakPtr()));
120 TransitionToState(RemoteDeviceLifeCycle::State::AUTHENTICATING
);
123 void RemoteDeviceLifeCycleImpl::OnAuthenticationResult(
124 Authenticator::Result result
,
125 scoped_ptr
<SecureContext
> secure_context
) {
126 DCHECK(state_
== RemoteDeviceLifeCycle::State::AUTHENTICATING
);
127 if (result
!= Authenticator::Result::SUCCESS
) {
128 PA_LOG(WARNING
) << "Waiting " << kAuthenticationRecoveryTimeSeconds
129 << " seconds to retry after authentication failure.";
130 connection_
->Disconnect();
131 authentication_recovery_timer_
.Start(
133 base::TimeDelta::FromSeconds(kAuthenticationRecoveryTimeSeconds
), this,
134 &RemoteDeviceLifeCycleImpl::FindConnection
);
135 TransitionToState(RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED
);
139 // Create the MessengerImpl asynchronously. |messenger_| registers itself as
141 // observer of |connection_|, so creating it synchronously would
142 // trigger |OnSendComplete()| as an observer call for |messenger_|.
143 secure_context_
= secure_context
.Pass();
144 base::ThreadTaskRunnerHandle::Get()->PostTask(
145 FROM_HERE
, base::Bind(&RemoteDeviceLifeCycleImpl::CreateMessenger
,
146 weak_ptr_factory_
.GetWeakPtr()));
149 void RemoteDeviceLifeCycleImpl::CreateMessenger() {
150 DCHECK(state_
== RemoteDeviceLifeCycle::State::AUTHENTICATING
);
151 DCHECK(secure_context_
);
153 new MessengerImpl(connection_
.Pass(), secure_context_
.Pass()));
154 messenger_
->AddObserver(this);
156 TransitionToState(RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
);
159 void RemoteDeviceLifeCycleImpl::OnDisconnected() {
160 DCHECK(state_
== RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
);
164 } // namespace proximity_auth