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

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

Issue 1116963002: Bluetooth low energy connection. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressing tengs comments Created 5 years, 7 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.h"
6
7 #include "base/bind.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/weak_ptr.h"
10 #include "components/proximity_auth/ble/fake_wire_message.h"
11 #include "components/proximity_auth/connection_finder.h"
12 #include "components/proximity_auth/wire_message.h"
13 #include "device/bluetooth/bluetooth_adapter.h"
14 #include "device/bluetooth/bluetooth_device.h"
15 #include "device/bluetooth/bluetooth_gatt_characteristic.h"
16 #include "device/bluetooth/bluetooth_gatt_connection.h"
17 #include "device/bluetooth/bluetooth_gatt_notify_session.h"
18 #include "device/bluetooth/bluetooth_uuid.h"
19
20 using device::BluetoothAdapter;
21 using device::BluetoothDevice;
22 using device::BluetoothGattConnection;
23 using device::BluetoothGattService;
24 using device::BluetoothGattCharacteristic;
25 using device::BluetoothGattNotifySession;
26 using device::BluetoothUUID;
27
28 namespace proximity_auth {
29
30 BluetoothLowEnergyConnection::BluetoothLowEnergyConnection(
31 const RemoteDevice& device,
32 scoped_refptr<device::BluetoothAdapter> adapter,
33 const BluetoothUUID remote_service_uuid,
34 const BluetoothUUID to_peripheral_char_uuid,
35 const BluetoothUUID from_peripheral_char_uuid,
36 scoped_ptr<BluetoothGattConnection> gatt_connection)
37 : Connection(device),
38 adapter_(adapter),
39 remote_service_uuid_(remote_service_uuid),
40 to_peripheral_char_({to_peripheral_char_uuid, ""}),
41 from_peripheral_char_({from_peripheral_char_uuid, ""}),
42 connection_(gatt_connection.Pass()),
43 notify_session_pending_(false),
44 connect_signal_response_pending_(false),
45 weak_ptr_factory_(this) {
46 DCHECK(connection_);
47 DCHECK(adapter_);
48 DCHECK(adapter_->IsInitialized());
49
50 SetStatus(IN_PROGRESS);
51
52 BluetoothGattService* service = GetRemoteService();
53 if (service) {
54 std::vector<device::BluetoothGattCharacteristic*> characteristics =
55 service->GetCharacteristics();
56 for (auto iter = characteristics.begin(); iter != characteristics.end();
57 iter++) {
58 HandleCharacteristicUpdate(*iter);
59 }
60 }
61
62 adapter_->AddObserver(this);
63 }
64
65 BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {
66 Disconnect();
67 if (adapter_) {
68 adapter_->RemoveObserver(this);
69 adapter_ = NULL;
70 }
71 }
72
73 void BluetoothLowEnergyConnection::Connect() {
74 NOTREACHED();
75 }
76
77 // This actually forgets the remote BLE device. This is safe as long as we only
78 // connect to BLE devices advertising the SmartLock service (assuming this
79 // device has no other being used).
80 void BluetoothLowEnergyConnection::Disconnect() {
81 StopNotifySession();
82 SetStatus(DISCONNECTED);
83 if (connection_) {
84 connection_.reset();
85 BluetoothDevice* device = GetRemoteDevice();
86 if (device) {
87 VLOG(1) << "Forget device " << device->GetAddress();
88 device->Forget(base::Bind(&base::DoNothing));
89 }
90 }
91 }
92
93 // TODO(sacomoto): Send a SmartLock BLE socket incoming signal. Implement a
94 // sender with full support for messages larger than a single characteristic
95 // value.
96 void BluetoothLowEnergyConnection::SendMessageImpl(
97 scoped_ptr<WireMessage> message) {
98 DCHECK(!GetGattCharacteristic(to_peripheral_char_.id));
99 VLOG(1) << "Sending message " << message->Serialize();
100
101 std::string serialized_message = message->Serialize();
102 std::vector<uint8> bytes(serialized_message.begin(),
103 serialized_message.end());
104
105 GetGattCharacteristic(to_peripheral_char_.id)
106 ->WriteRemoteCharacteristic(
107 bytes, base::Bind(&base::DoNothing),
108 base::Bind(
109 &BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError,
110 weak_ptr_factory_.GetWeakPtr()));
111 }
112
113 void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter* adapter,
114 BluetoothDevice* device) {
115 if (device && device->GetAddress() == GetRemoteDeviceAddress()) {
116 VLOG(1) << "Device removed " << GetRemoteDeviceAddress();
117 Disconnect();
118 }
119 }
120
121 void BluetoothLowEnergyConnection::GattDiscoveryCompleteForService(
122 BluetoothAdapter* adapter,
123 BluetoothGattService* service) {
124 if (service && service->GetUUID() == remote_service_uuid_) {
125 VLOG(1) << "All characteristics discovered for "
126 << remote_service_uuid_.canonical_value();
127
128 std::vector<device::BluetoothGattCharacteristic*> characteristics =
129 service->GetCharacteristics();
130 for (auto iter = characteristics.begin(); iter != characteristics.end();
131 iter++) {
132 HandleCharacteristicUpdate(*iter);
133 }
134
135 if (to_peripheral_char_.id.empty() || from_peripheral_char_.id.empty()) {
136 VLOG(1) << "Connection error, missing characteristics for SmartLock "
137 "service.\n"
138 << (to_peripheral_char_.id.empty()
139 ? to_peripheral_char_.uuid.canonical_value()
140 : "")
141 << (from_peripheral_char_.id.empty()
142 ? ", " + from_peripheral_char_.uuid.canonical_value()
143 : "") << " not found.";
144 Disconnect();
145 }
146 }
147 }
148
149 void BluetoothLowEnergyConnection::GattCharacteristicAdded(
150 BluetoothAdapter* adapter,
151 BluetoothGattCharacteristic* characteristic) {
152 VLOG(1) << "New char found: " << characteristic->GetUUID().canonical_value();
153 HandleCharacteristicUpdate(characteristic);
154 }
155
156 // TODO(sacomoto): Parse the SmartLock BLE socket incoming signal. Implement a
157 // receiver with full suport for messages larger than a single characteristic
158 // value.
159 void BluetoothLowEnergyConnection::GattCharacteristicValueChanged(
160 BluetoothAdapter* adapter,
161 BluetoothGattCharacteristic* characteristic,
162 const std::vector<uint8>& value) {
163 DCHECK_EQ(adapter, adapter_.get());
164
165 VLOG(1) << "Characteristic value changed: "
166 << characteristic->GetUUID().canonical_value();
167
168 if (characteristic->GetIdentifier() == from_peripheral_char_.id) {
169 const ControlSignal signal = static_cast<ControlSignal>(ToUint32(value));
170
171 switch (signal) {
172 case ControlSignal::kInvitationResponseSignal:
173 connect_signal_response_pending_ = false;
174 CompleteConnection();
175 break;
176 case ControlSignal::kInviteToConnectSignal:
177 case ControlSignal::kSendSignal:
178 // TODO(sacomoto): Actually handle the message and call OnBytesReceived
179 // when complete.
180 case ControlSignal::kDisconnectSignal:
181 Disconnect();
182 break;
183 }
184 }
185 }
186
187 scoped_ptr<WireMessage> BluetoothLowEnergyConnection::DeserializeWireMessage(
188 bool* is_incomplete_message) {
189 return FakeWireMessage::Deserialize(received_bytes(), is_incomplete_message);
190 }
191
192 void BluetoothLowEnergyConnection::HandleCharacteristicUpdate(
193 BluetoothGattCharacteristic* characteristic) {
194 // Checks if |characteristic| is equal to |from_peripheral_char_| or
195 // |to_peripheral_char_|.
196 UpdateCharacteristicsStatus(characteristic);
197
198 // Starts a notify session for |from_peripheral_char_|.
199 if (characteristic->GetIdentifier() == from_peripheral_char_.id)
200 StartNotifySession();
201
202 // Sends a invite to connect signal if ready.
203 SendInviteToConnectSignal();
204 }
205
206 void BluetoothLowEnergyConnection::CompleteConnection() {
207 if (status() == IN_PROGRESS && !connect_signal_response_pending_ &&
208 !to_peripheral_char_.id.empty() && !from_peripheral_char_.id.empty() &&
209 notify_session_) {
210 VLOG(1) << "Connection completed";
211 SetStatus(CONNECTED);
212 }
213 }
214
215 void BluetoothLowEnergyConnection::StartNotifySession() {
216 BluetoothGattCharacteristic* characteristic =
217 GetGattCharacteristic(from_peripheral_char_.id);
218 if (!characteristic) {
219 VLOG(1) << "Characteristic " << from_peripheral_char_.uuid.canonical_value()
220 << " not found.";
221 return;
222 }
223
224 if (notify_session_ || notify_session_pending_) {
225 VLOG(1) << "Notify session already started.";
226 return;
227 }
228
229 notify_session_pending_ = true;
230 characteristic->StartNotifySession(
231 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionStarted,
232 weak_ptr_factory_.GetWeakPtr()),
233 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionError,
234 weak_ptr_factory_.GetWeakPtr()));
235 }
236
237 void BluetoothLowEnergyConnection::OnNotifySessionError(
238 BluetoothGattService::GattErrorCode error) {
239 VLOG(1) << "Error starting notification session: " << error;
240 notify_session_pending_ = false;
241 }
242
243 void BluetoothLowEnergyConnection::OnNotifySessionStarted(
244 scoped_ptr<BluetoothGattNotifySession> notify_session) {
245 VLOG(1) << "Notification session started "
246 << notify_session->GetCharacteristicIdentifier();
247 notify_session_ = notify_session.Pass();
248 notify_session_pending_ = false;
249
250 // Sends an invite to connect signal if ready.
251 SendInviteToConnectSignal();
252 }
253
254 void BluetoothLowEnergyConnection::StopNotifySession() {
255 if (notify_session_) {
256 notify_session_->Stop(base::Bind(&base::DoNothing));
257 notify_session_.reset();
258 }
259 }
260
261 void BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError(
262 BluetoothGattService::GattErrorCode error) {
263 VLOG(1) << "Error writing characteristic"
264 << to_peripheral_char_.uuid.canonical_value();
265 }
266
267 void BluetoothLowEnergyConnection::SendInviteToConnectSignal() {
268 if (status() == IN_PROGRESS && !connect_signal_response_pending_ &&
269 !to_peripheral_char_.id.empty() && !from_peripheral_char_.id.empty() &&
270 notify_session_) {
271 VLOG(1) << "Sending invite to connect signal";
272 connect_signal_response_pending_ = true;
273
274 // The connection status is not CONNECTED yet, so in order to bypass the
275 // check in SendMessage implementation we need to send the message using the
276 // private implementation.
277 SendMessageImpl(scoped_ptr<FakeWireMessage>(new FakeWireMessage(
278 ToString(static_cast<uint32>(ControlSignal::kInviteToConnectSignal)))));
279 }
280 }
281
282 void BluetoothLowEnergyConnection::UpdateCharacteristicsStatus(
283 BluetoothGattCharacteristic* characteristic) {
284 if (characteristic) {
285 BluetoothUUID uuid = characteristic->GetUUID();
286 if (to_peripheral_char_.uuid == uuid)
287 to_peripheral_char_.id = characteristic->GetIdentifier();
288 if (from_peripheral_char_.uuid == uuid)
289 from_peripheral_char_.id = characteristic->GetIdentifier();
290
291 BluetoothGattService* service = characteristic->GetService();
292 if (service && service->GetUUID() == remote_service_uuid_)
293 remote_service_id_ = service->GetIdentifier();
294 }
295 }
296
297 const std::string& BluetoothLowEnergyConnection::GetRemoteDeviceAddress() {
298 return remote_device().bluetooth_address;
299 }
300
301 BluetoothDevice* BluetoothLowEnergyConnection::GetRemoteDevice() {
302 if (!adapter_ || !adapter_->IsInitialized()) {
303 VLOG(1) << "adapter not ready";
304 return NULL;
305 }
306 return adapter_->GetDevice(GetRemoteDeviceAddress());
307 }
308
309 BluetoothGattService* BluetoothLowEnergyConnection::GetRemoteService() {
310 BluetoothDevice* remote_device = GetRemoteDevice();
311 if (!remote_device) {
312 VLOG(1) << "device not found";
313 return NULL;
314 }
315 if (remote_service_id_.empty()) {
316 std::vector<BluetoothGattService*> services =
317 remote_device->GetGattServices();
318 for (auto iter = services.begin(); iter != services.end(); ++iter)
319 if ((*iter)->GetUUID() == remote_service_uuid_) {
320 remote_service_id_ = (*iter)->GetIdentifier();
321 break;
322 }
323 }
324 return remote_device->GetGattService(remote_service_id_);
325 }
326
327 BluetoothGattCharacteristic*
328 BluetoothLowEnergyConnection::GetGattCharacteristic(
329 const std::string& gatt_characteristic) {
330 BluetoothGattService* remote_service = GetRemoteService();
331 if (!remote_service) {
332 VLOG(1) << "service not found";
333 return NULL;
334 }
335 return remote_service->GetCharacteristic(gatt_characteristic);
336 }
337
338 // TODO(sacomoto): make this robust to byte ordering in both sides of the
339 // SmartLock BLE socket.
340 uint32 BluetoothLowEnergyConnection::ToUint32(const std::vector<uint8>& bytes) {
341 return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
342 }
343
344 // TODO(sacomoto): make this robust to byte ordering in both sides of the
345 // SmartLock BLE socket.
346 const std::string BluetoothLowEnergyConnection::ToString(const uint32 value) {
347 char bytes[4] = {};
348
349 bytes[0] = static_cast<uint8>(value);
350 bytes[1] = static_cast<uint8>(value >> 8);
351 bytes[2] = static_cast<uint8>(value >> 12);
352 bytes[3] = static_cast<uint8>(value >> 24);
353
354 return std::string(bytes);
355 }
356
357 } // namespace proximity_auth
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698