Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc

Issue 2841743003: [EasyUnlock] Update BluetoothLowEnergyConnectionFinder to look for EIDs. (Closed)
Patch Set: remote static initializer Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
5 #include "components/proximity_auth/ble/bluetooth_low_energy_connection_finder.h "
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "components/cryptauth/bluetooth_throttler.h"
19 #include "components/cryptauth/connection.h"
20 #include "components/proximity_auth/ble/bluetooth_low_energy_connection.h"
21 #include "components/proximity_auth/ble/bluetooth_low_energy_device_whitelist.h"
22 #include "components/proximity_auth/logging/logging.h"
23 #include "device/bluetooth/bluetooth_adapter_factory.h"
24 #include "device/bluetooth/bluetooth_common.h"
25 #include "device/bluetooth/bluetooth_device.h"
26 #include "device/bluetooth/bluetooth_discovery_session.h"
27 #include "device/bluetooth/bluetooth_uuid.h"
28
29 using device::BluetoothAdapter;
30 using device::BluetoothDevice;
31 using device::BluetoothGattConnection;
32 using device::BluetoothDiscoveryFilter;
33
34 namespace proximity_auth {
35 namespace {
36 const int kMinDiscoveryRSSI = -90;
37 } // namespace
38
39 BluetoothLowEnergyConnectionFinder::BluetoothLowEnergyConnectionFinder(
40 const cryptauth::RemoteDevice remote_device,
41 const std::string& remote_service_uuid,
42 FinderStrategy finder_strategy,
43 const BluetoothLowEnergyDeviceWhitelist* device_whitelist,
44 cryptauth::BluetoothThrottler* bluetooth_throttler,
45 int max_number_of_tries)
46 : remote_device_(remote_device),
47 remote_service_uuid_(device::BluetoothUUID(remote_service_uuid)),
48 finder_strategy_(finder_strategy),
49 device_whitelist_(device_whitelist),
50 bluetooth_throttler_(bluetooth_throttler),
51 max_number_of_tries_(max_number_of_tries),
52 weak_ptr_factory_(this) {
53 DCHECK(finder_strategy_ == FIND_ANY_DEVICE ||
54 !remote_device.bluetooth_address.empty());
55 }
56
57 BluetoothLowEnergyConnectionFinder::~BluetoothLowEnergyConnectionFinder() {
58 if (discovery_session_) {
59 StopDiscoverySession();
60 }
61
62 if (connection_) {
63 connection_->RemoveObserver(this);
64 connection_.reset();
65 }
66
67 if (adapter_) {
68 adapter_->RemoveObserver(this);
69 adapter_ = NULL;
70 }
71 }
72
73 void BluetoothLowEnergyConnectionFinder::Find(
74 const cryptauth::ConnectionFinder::ConnectionCallback&
75 connection_callback) {
76 if (!device::BluetoothAdapterFactory::IsBluetoothSupported()) {
77 PA_LOG(WARNING) << "Bluetooth is unsupported on this platform. Aborting.";
78 return;
79 }
80 PA_LOG(INFO) << "Finding connection";
81
82 connection_callback_ = connection_callback;
83
84 device::BluetoothAdapterFactory::GetAdapter(
85 base::Bind(&BluetoothLowEnergyConnectionFinder::OnAdapterInitialized,
86 weak_ptr_factory_.GetWeakPtr()));
87 }
88
89 // It's not necessary to observe |AdapterPresentChanged| too. When |adapter_| is
90 // present, but not powered, it's not possible to scan for new devices.
91 void BluetoothLowEnergyConnectionFinder::AdapterPoweredChanged(
92 BluetoothAdapter* adapter,
93 bool powered) {
94 DCHECK_EQ(adapter_.get(), adapter);
95 PA_LOG(INFO) << "Adapter powered: " << powered;
96
97 // Important: do not rely on |adapter->IsDiscoverying()| to verify if there is
98 // an active discovery session. We need to create our own with an specific
99 // filter.
100 if (powered && (!discovery_session_ || !discovery_session_->IsActive()))
101 StartDiscoverySession();
102 }
103
104 void BluetoothLowEnergyConnectionFinder::DeviceAdded(BluetoothAdapter* adapter,
105 BluetoothDevice* device) {
106 DCHECK_EQ(adapter_.get(), adapter);
107 DCHECK(device);
108
109 // Note: Only consider |device| when it was actually added/updated during a
110 // scanning, otherwise the device is stale and the GATT connection will fail.
111 // For instance, when |adapter_| change status from unpowered to powered,
112 // |DeviceAdded| is called for each paired |device|.
113 if (adapter_->IsPowered() && discovery_session_ &&
114 discovery_session_->IsActive())
115 HandleDeviceUpdated(device);
116 }
117
118 void BluetoothLowEnergyConnectionFinder::DeviceChanged(
119 BluetoothAdapter* adapter,
120 BluetoothDevice* device) {
121 DCHECK_EQ(adapter_.get(), adapter);
122 DCHECK(device);
123
124 // Note: Only consider |device| when it was actually added/updated during a
125 // scanning, otherwise the device is stale and the GATT connection will fail.
126 // For instance, when |adapter_| change status from unpowered to powered,
127 // |DeviceAdded| is called for each paired |device|.
128 if (adapter_->IsPowered() && discovery_session_ &&
129 discovery_session_->IsActive())
130 HandleDeviceUpdated(device);
131 }
132
133 void BluetoothLowEnergyConnectionFinder::HandleDeviceUpdated(
134 BluetoothDevice* device) {
135 // Ensuring only one call to |CreateConnection()| is made. A new |connection_|
136 // can be created only when the previous one disconnects, triggering a call to
137 // |OnConnectionStatusChanged|.
138 if (connection_)
139 return;
140
141 if (IsRightDevice(device)) {
142 PA_LOG(INFO) << "Connecting to device " << device->GetAddress()
143 << " with service (" << HasService(device)
144 << ") and is paired (" << device->IsPaired();
145
146 connection_ = CreateConnection(device->GetAddress());
147 connection_->AddObserver(this);
148 connection_->Connect();
149
150 StopDiscoverySession();
151 }
152 }
153
154 bool BluetoothLowEnergyConnectionFinder::IsRightDevice(
155 BluetoothDevice* device) {
156 if (!device)
157 return false;
158
159 // TODO(sacomoto): Remove it when ProximityAuthBleSystem is not needed
160 // anymore.
161 if (device_whitelist_)
162 return device->IsPaired() &&
163 (HasService(device) ||
164 device_whitelist_->HasDeviceWithAddress(device->GetAddress()));
165
166 // The device should be paired when looking for BLE devices by bluetooth
167 // address.
168 if (finder_strategy_ == FIND_PAIRED_DEVICE)
169 return device->IsPaired() &&
170 device->GetAddress() == remote_device_.bluetooth_address;
171 return HasService(device);
172 }
173
174 bool BluetoothLowEnergyConnectionFinder::HasService(
175 BluetoothDevice* remote_device) {
176 if (!remote_device) {
177 return false;
178 }
179
180 BluetoothDevice::UUIDSet uuids = remote_device->GetUUIDs();
181
182 PA_LOG(INFO) << "Device " << remote_device->GetAddress() << " has "
183 << uuids.size() << " services.";
184 return base::ContainsKey(uuids, remote_service_uuid_);
185 }
186
187 void BluetoothLowEnergyConnectionFinder::OnAdapterInitialized(
188 scoped_refptr<BluetoothAdapter> adapter) {
189 PA_LOG(INFO) << "Adapter ready";
190
191 adapter_ = adapter;
192 adapter_->AddObserver(this);
193
194 // This is important for debugging. To eliminate the case where the device was
195 // removed (forgotten) by the user, or BlueZ didn't load the device correctly.
196 if (finder_strategy_ == FIND_PAIRED_DEVICE) {
197 PA_LOG(INFO) << "Looking for paired device: "
198 << remote_device_.bluetooth_address;
199 for (const auto* device : adapter_->GetDevices()) {
200 if (device->IsPaired())
201 PA_LOG(INFO) << device->GetAddress() << " is paired";
202 }
203 }
204
205 // Note: It's possible to connect to the paired directly, so when using
206 // FIND_PAIRED_DEVICE strategy this is not necessary. However, the discovery
207 // doesn't add a lot of latency, and the makes the code path for both
208 // strategies more similar.
209 StartDiscoverySession();
210 }
211
212 void BluetoothLowEnergyConnectionFinder::OnDiscoverySessionStarted(
213 std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) {
214 PA_LOG(INFO) << "Discovery session started";
215 discovery_session_ = std::move(discovery_session);
216 }
217
218 void BluetoothLowEnergyConnectionFinder::OnStartDiscoverySessionError() {
219 PA_LOG(WARNING) << "Error starting discovery session";
220 }
221
222 void BluetoothLowEnergyConnectionFinder::StartDiscoverySession() {
223 DCHECK(adapter_);
224 if (discovery_session_ && discovery_session_->IsActive()) {
225 PA_LOG(INFO) << "Discovery session already active";
226 return;
227 }
228
229 // Discover only low energy (LE) devices with strong enough signal.
230 std::unique_ptr<BluetoothDiscoveryFilter> filter(
231 new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE));
232 filter->SetRSSI(kMinDiscoveryRSSI);
233
234 adapter_->StartDiscoverySessionWithFilter(
235 std::move(filter),
236 base::Bind(&BluetoothLowEnergyConnectionFinder::OnDiscoverySessionStarted,
237 weak_ptr_factory_.GetWeakPtr()),
238 base::Bind(
239 &BluetoothLowEnergyConnectionFinder::OnStartDiscoverySessionError,
240 weak_ptr_factory_.GetWeakPtr()));
241 }
242
243 void BluetoothLowEnergyConnectionFinder::StopDiscoverySession() {
244 PA_LOG(INFO) << "Stopping discovery session";
245 // Destroying the discovery session also stops it.
246 discovery_session_.reset();
247 }
248
249 std::unique_ptr<cryptauth::Connection>
250 BluetoothLowEnergyConnectionFinder::CreateConnection(
251 const std::string& device_address) {
252 DCHECK(remote_device_.bluetooth_address.empty() ||
253 remote_device_.bluetooth_address == device_address);
254 remote_device_.bluetooth_address = device_address;
255 return base::MakeUnique<BluetoothLowEnergyConnection>(
256 remote_device_, adapter_, remote_service_uuid_, bluetooth_throttler_,
257 max_number_of_tries_);
258 }
259
260 void BluetoothLowEnergyConnectionFinder::OnConnectionStatusChanged(
261 cryptauth::Connection* connection,
262 cryptauth::Connection::Status old_status,
263 cryptauth::Connection::Status new_status) {
264 DCHECK_EQ(connection, connection_.get());
265 PA_LOG(INFO) << "OnConnectionStatusChanged: " << old_status << " -> "
266 << new_status;
267
268 if (!connection_callback_.is_null() && connection_->IsConnected()) {
269 adapter_->RemoveObserver(this);
270 connection_->RemoveObserver(this);
271
272 // If we invoke the callback now, the callback function may install its own
273 // observer to |connection_|. Because we are in the ConnectionObserver
274 // callstack, this new observer will receive this connection event.
275 // Therefore, we need to invoke the callback or restart discovery
276 // asynchronously.
277 base::ThreadTaskRunnerHandle::Get()->PostTask(
278 FROM_HERE,
279 base::Bind(&BluetoothLowEnergyConnectionFinder::InvokeCallbackAsync,
280 weak_ptr_factory_.GetWeakPtr()));
281 } else if (old_status == cryptauth::Connection::IN_PROGRESS) {
282 PA_LOG(WARNING) << "Connection failed. Retrying.";
283 base::ThreadTaskRunnerHandle::Get()->PostTask(
284 FROM_HERE,
285 base::Bind(
286 &BluetoothLowEnergyConnectionFinder::RestartDiscoverySessionAsync,
287 weak_ptr_factory_.GetWeakPtr()));
288 }
289 }
290
291 void BluetoothLowEnergyConnectionFinder::RestartDiscoverySessionAsync() {
292 PA_LOG(INFO) << "Restarting discovery session.";
293 connection_.reset();
294 if (!discovery_session_ || !discovery_session_->IsActive())
295 StartDiscoverySession();
296 }
297
298 BluetoothDevice* BluetoothLowEnergyConnectionFinder::GetDevice(
299 const std::string& device_address) {
300 // It's not possible to simply use
301 // |adapter_->GetDevice(GetRemoteDeviceAddress())| to find the device with MAC
302 // address |GetRemoteDeviceAddress()|. For paired devices,
303 // BluetoothAdapter::GetDevice(XXX) searches for the temporary MAC address
304 // XXX, whereas |remote_device_.bluetooth_address| is the real MAC address.
305 // This is a bug in the way device::BluetoothAdapter is storing the devices
306 // (see crbug.com/497841).
307 std::vector<BluetoothDevice*> devices = adapter_->GetDevices();
308 for (auto* device : devices) {
309 if (device->GetAddress() == device_address)
310 return device;
311 }
312 return nullptr;
313 }
314
315 void BluetoothLowEnergyConnectionFinder::InvokeCallbackAsync() {
316 connection_callback_.Run(std::move(connection_));
317 }
318
319 } // namespace proximity_auth
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698