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

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: Refactoring the connection callback 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 BluetoothUUID remote_service_uuid,
34 const std::string& to_peripheral_char_uuid,
35 const std::string& 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_uuid_(to_peripheral_char_uuid),
41 from_peripheral_char_uuid_(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 adapter_->AddObserver(this);
Tim Song 2015/05/11 08:02:39 Are all services going to be discovered as soon as
sacomoto 2015/05/11 12:04:04 Yes, you are right. We should scan the services a
52 }
53
54 BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {
55 Disconnect();
56 if (adapter_) {
57 adapter_->RemoveObserver(this);
58 adapter_ = NULL;
59 }
60 }
61
62 void BluetoothLowEnergyConnection::Connect() {
63 NOTREACHED();
64 }
65
66 // This actually forgets the remote BLE device. This is safe as long as we only
67 // connect to BLE devices advertising the SmartLock service (assuming this
68 // device has no other being used).
69 void BluetoothLowEnergyConnection::Disconnect() {
70 StopNotifySession();
71 SetStatus(DISCONNECTED);
72 if (connection_) {
73 connection_.reset();
74 BluetoothDevice* device = GetRemoteDevice();
75 if (device) {
76 VLOG(1) << "Forget device " << device->GetAddress();
77 device->Forget(base::Bind(&base::DoNothing));
78 }
79 }
80 }
81
82 // TODO(sacomoto): Send a SmartLock BLE socket incoming signal. Implement a
83 // sender with full support for messages larger than a single characteristic
84 // value.
85 void BluetoothLowEnergyConnection::SendMessageImpl(
86 scoped_ptr<WireMessage> message) {
87 DCHECK(!GetGattCharacteristic(to_peripheral_char_id_));
88 VLOG(1) << "Sending message " << message->Serialize();
89
90 std::string serialized_message = message->Serialize();
91 std::vector<uint8> bytes(serialized_message.begin(),
92 serialized_message.end());
93
94 GetGattCharacteristic(to_peripheral_char_id_)
95 ->WriteRemoteCharacteristic(
96 bytes, base::Bind(&base::DoNothing),
97 base::Bind(
98 &BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError,
99 weak_ptr_factory_.GetWeakPtr()));
100 }
101
102 void BluetoothLowEnergyConnection::DeviceRemoved(BluetoothAdapter* adapter,
103 BluetoothDevice* device) {
104 if (device && device->GetAddress() == GetRemoteDeviceAddress()) {
105 VLOG(1) << "Device removed " << GetRemoteDeviceAddress();
106 Disconnect();
107 }
108 }
109
110 void BluetoothLowEnergyConnection::GattDiscoveryCompleteForService(
111 BluetoothAdapter* adapter,
112 BluetoothGattService* service) {
113 if (service && service->GetUUID() == remote_service_uuid_) {
114 VLOG(1) << "All characteristics discovered for "
115 << remote_service_uuid_.canonical_value();
116
117 std::vector<device::BluetoothGattCharacteristic*> characteristics =
118 service->GetCharacteristics();
119 for (auto iter = characteristics.begin(); iter != characteristics.end();
120 iter++) {
121 HandleCharacteristicUpdate(*iter);
122 }
123
124 if (to_peripheral_char_id_.empty() || from_peripheral_char_id_.empty()) {
125 VLOG(1) << "Connection error, missing characteristics for SmartLock "
126 "service.\n"
127 << (to_peripheral_char_id_.empty() ? to_peripheral_char_uuid_
128 : "")
129 << (from_peripheral_char_id_.empty()
130 ? ", " + from_peripheral_char_uuid_
131 : "") << " not found.";
132 Disconnect();
133 }
134 }
135 }
136
137 void BluetoothLowEnergyConnection::GattCharacteristicAdded(
138 BluetoothAdapter* adapter,
139 BluetoothGattCharacteristic* characteristic) {
140 VLOG(1) << "new char found: " << characteristic->GetUUID().canonical_value();
141 HandleCharacteristicUpdate(characteristic);
Tim Song 2015/05/11 08:02:39 Is it correct to call HandleCharacteristicUpdate()
sacomoto 2015/05/11 12:04:04 This was intentional. The idea was to have the con
Tim Song 2015/05/12 03:02:46 Thanks for the explanation. In this case, do you e
sacomoto 2015/05/12 07:23:19 Yes, we still need to override GattDiscoveryComple
Tim Song 2015/05/13 02:36:55 Can we at least get rid of the for loop iterating
142 }
143
144 // TODO(sacomoto): Parse the SmartLock BLE socket incoming signal. Implement a
145 // receiver with full suport for messages larger than a single characteristic
146 // value.
147 void BluetoothLowEnergyConnection::GattCharacteristicValueChanged(
148 BluetoothAdapter* adapter,
149 BluetoothGattCharacteristic* characteristic,
150 const std::vector<uint8>& value) {
151 DCHECK_EQ(adapter, adapter_.get());
152
153 VLOG(1) << "Characteristic value changed: "
154 << characteristic->GetUUID().canonical_value();
155
156 if (characteristic->GetIdentifier() == from_peripheral_char_id_) {
157 const ControlSignal signal =
158 static_cast<ControlSignal>(ExtractUint32(value));
159
160 switch (signal) {
161 case kInvitationResponseSignal:
162 connect_signal_response_pending_ = false;
163 CompleteConnection();
164 break;
165 case kInviteToConnectSignal:
166 case kSendSignal:
167 // TODO(sacomoto): Actually handle the message and call OnBytesReceived
168 // when complete.
169 case kDisconnectSignal:
170 Disconnect();
171 break;
172 }
173 }
174 }
175
176 scoped_ptr<WireMessage> BluetoothLowEnergyConnection::DeserializeWireMessage(
177 bool* is_incomplete_message) {
178 return FakeWireMessage::Deserialize(received_bytes(), is_incomplete_message);
179 }
180
181 void BluetoothLowEnergyConnection::HandleCharacteristicUpdate(
182 BluetoothGattCharacteristic* characteristic) {
183 // Checks if |characteristic| is equal to |from_peripheral_char_uuid_| or
184 // |to_peripheral_char_uuid_|.
185 UpdateCharacteristicsStatus(characteristic);
186
187 // Starts a notify session for |from_peripheral_char_uuid_|.
188 if (characteristic->GetIdentifier() == from_peripheral_char_id_)
189 StartNotifySession();
190
191 // Sends a invite to connect signal if ready.
192 SendInviteToConnectSignal();
193 }
194
195 void BluetoothLowEnergyConnection::CompleteConnection() {
196 if (status() == IN_PROGRESS && !connect_signal_response_pending_ &&
197 !to_peripheral_char_id_.empty() && !from_peripheral_char_id_.empty() &&
198 notify_session_) {
199 VLOG(1) << "Connection completed";
200 SetStatus(CONNECTED);
201 }
202 }
203
204 void BluetoothLowEnergyConnection::StartNotifySession() {
205 BluetoothGattCharacteristic* characteristic =
206 GetGattCharacteristic(from_peripheral_char_id_);
207 if (!characteristic) {
208 VLOG(1) << "Characteristic " << from_peripheral_char_uuid_ << " not found.";
209 return;
210 }
211
212 if (notify_session_ || notify_session_pending_) {
213 VLOG(1) << "Notify session already started.";
214 return;
215 }
216
217 notify_session_pending_ = true;
218 characteristic->StartNotifySession(
219 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionStarted,
220 weak_ptr_factory_.GetWeakPtr()),
221 base::Bind(&BluetoothLowEnergyConnection::OnNotifySessionError,
222 weak_ptr_factory_.GetWeakPtr()));
223 }
224
225 void BluetoothLowEnergyConnection::OnNotifySessionError(
226 BluetoothGattService::GattErrorCode error) {
227 VLOG(1) << "Error starting notification session: " << error;
228 notify_session_pending_ = false;
229 }
230
231 void BluetoothLowEnergyConnection::OnNotifySessionStarted(
232 scoped_ptr<BluetoothGattNotifySession> notify_session) {
233 VLOG(1) << "Notification session started "
234 << notify_session->GetCharacteristicIdentifier();
235 notify_session_ = notify_session.Pass();
236 notify_session_pending_ = false;
237
238 // Sends an invite to connect signal if ready.
239 SendInviteToConnectSignal();
240 }
241
242 void BluetoothLowEnergyConnection::StopNotifySession() {
243 if (notify_session_) {
244 notify_session_->Stop(base::Bind(&base::DoNothing));
245 notify_session_.reset();
246 }
247 }
248
249 void BluetoothLowEnergyConnection::OnWriteRemoteCharacteristicError(
250 BluetoothGattService::GattErrorCode error) {
251 VLOG(1) << "Error writing characteristic" << to_peripheral_char_uuid_;
252 }
253
254 void BluetoothLowEnergyConnection::SendInviteToConnectSignal() {
255 if (status() == IN_PROGRESS && !connect_signal_response_pending_ &&
256 !to_peripheral_char_id_.empty() && !from_peripheral_char_id_.empty() &&
257 notify_session_) {
258 VLOG(1) << "Sending invite to connect signal";
259 connect_signal_response_pending_ = true;
260 const char connect_signal[4] = {};
Tim Song 2015/05/11 08:02:39 You should use use the kInviteToConnectSignal valu
sacomoto 2015/05/11 12:04:04 Done.
261
262 // The connection status is not CONNECTED yet, so in order to bypass the
263 // check in SendMessage implementation we need to send the message using the
264 // private implementation.
265 SendMessageImpl(
266 scoped_ptr<FakeWireMessage>(new FakeWireMessage(connect_signal)));
267 }
268 }
269
270 void BluetoothLowEnergyConnection::UpdateCharacteristicsStatus(
271 BluetoothGattCharacteristic* characteristic) {
272 if (characteristic) {
273 std::string canonical_value = characteristic->GetUUID().canonical_value();
274 VLOG(1) << canonical_value;
275 if (to_peripheral_char_uuid_ == canonical_value) {
276 to_peripheral_char_id_ = characteristic->GetIdentifier();
277 }
278 if (from_peripheral_char_uuid_ == canonical_value) {
Tim Song 2015/05/11 08:02:39 nit : please be consistent and remove the braces f
sacomoto 2015/05/11 12:04:03 Done.
279 from_peripheral_char_id_ = characteristic->GetIdentifier();
280 }
281 BluetoothGattService* service = characteristic->GetService();
282 if (service && service->GetUUID() == remote_service_uuid_)
283 remote_service_id_ = service->GetIdentifier();
284 }
285 }
286
287 const std::string& BluetoothLowEnergyConnection::GetRemoteDeviceAddress() {
288 return remote_device().bluetooth_address;
289 }
290
291 BluetoothDevice* BluetoothLowEnergyConnection::GetRemoteDevice() {
292 if (!adapter_ || !adapter_->IsInitialized()) {
293 VLOG(1) << "adapter not ready";
294 return NULL;
295 }
296 return adapter_->GetDevice(GetRemoteDeviceAddress());
297 }
298
299 BluetoothGattService* BluetoothLowEnergyConnection::GetRemoteService() {
300 BluetoothDevice* remote_device = GetRemoteDevice();
301 if (!remote_device) {
302 VLOG(1) << "device not found";
303 return NULL;
304 }
305 return remote_device->GetGattService(remote_service_id_);
306 }
307
308 BluetoothGattCharacteristic*
309 BluetoothLowEnergyConnection::GetGattCharacteristic(
310 const std::string& gatt_characteristic) {
311 BluetoothGattService* remote_service = GetRemoteService();
312 if (!remote_service) {
313 VLOG(1) << "service not found";
314 return NULL;
315 }
316 return remote_service->GetCharacteristic(gatt_characteristic);
317 }
318
319 // TODO(sacomoto): make this robust to byte ordering in both sides of the
320 // SmartLock BLE socket.
321 uint32 BluetoothLowEnergyConnection::ExtractUint32(
322 const std::vector<uint8>& bytes) {
323 return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
324 }
325
326 } // namespace proximity_auth
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698