OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h" | 5 #include "device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h" |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 25 matching lines...) Expand all Loading... |
36 } | 36 } |
37 return out << "]"; | 37 return out << "]"; |
38 } | 38 } |
39 | 39 |
40 } // namespace | 40 } // namespace |
41 | 41 |
42 BluetoothRemoteGattCharacteristicBlueZ::BluetoothRemoteGattCharacteristicBlueZ( | 42 BluetoothRemoteGattCharacteristicBlueZ::BluetoothRemoteGattCharacteristicBlueZ( |
43 BluetoothRemoteGattServiceBlueZ* service, | 43 BluetoothRemoteGattServiceBlueZ* service, |
44 const dbus::ObjectPath& object_path) | 44 const dbus::ObjectPath& object_path) |
45 : BluetoothGattCharacteristicBlueZ(object_path), | 45 : BluetoothGattCharacteristicBlueZ(object_path), |
46 num_notify_sessions_(0), | 46 has_notify_session_(false), |
47 notify_call_pending_(false), | |
48 service_(service), | 47 service_(service), |
49 weak_ptr_factory_(this) { | 48 weak_ptr_factory_(this) { |
50 VLOG(1) << "Creating remote GATT characteristic with identifier: " | 49 VLOG(1) << "Creating remote GATT characteristic with identifier: " |
51 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); | 50 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value(); |
52 bluez::BluezDBusManager::Get() | 51 bluez::BluezDBusManager::Get() |
53 ->GetBluetoothGattDescriptorClient() | 52 ->GetBluetoothGattDescriptorClient() |
54 ->AddObserver(this); | 53 ->AddObserver(this); |
55 | 54 |
56 // Add all known GATT characteristic descriptors. | 55 // Add all known GATT characteristic descriptors. |
57 const std::vector<dbus::ObjectPath>& gatt_descs = | 56 const std::vector<dbus::ObjectPath>& gatt_descs = |
58 bluez::BluezDBusManager::Get() | 57 bluez::BluezDBusManager::Get() |
59 ->GetBluetoothGattDescriptorClient() | 58 ->GetBluetoothGattDescriptorClient() |
60 ->GetDescriptors(); | 59 ->GetDescriptors(); |
61 for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin(); | 60 for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin(); |
62 iter != gatt_descs.end(); ++iter) | 61 iter != gatt_descs.end(); ++iter) |
63 GattDescriptorAdded(*iter); | 62 GattDescriptorAdded(*iter); |
64 } | 63 } |
65 | 64 |
66 BluetoothRemoteGattCharacteristicBlueZ:: | 65 BluetoothRemoteGattCharacteristicBlueZ:: |
67 ~BluetoothRemoteGattCharacteristicBlueZ() { | 66 ~BluetoothRemoteGattCharacteristicBlueZ() { |
68 bluez::BluezDBusManager::Get() | 67 bluez::BluezDBusManager::Get() |
69 ->GetBluetoothGattDescriptorClient() | 68 ->GetBluetoothGattDescriptorClient() |
70 ->RemoveObserver(this); | 69 ->RemoveObserver(this); |
71 | 70 |
72 // Clean up all the descriptors. There isn't much point in notifying service | 71 // Clean up all the descriptors. There isn't much point in notifying service |
73 // observers for each descriptor that gets removed, so just delete them. | 72 // observers for each descriptor that gets removed, so just delete them. |
74 for (DescriptorMap::iterator iter = descriptors_.begin(); | 73 for (DescriptorMap::iterator iter = descriptors_.begin(); |
75 iter != descriptors_.end(); ++iter) | 74 iter != descriptors_.end(); ++iter) |
76 delete iter->second; | 75 delete iter->second; |
77 | |
78 // Report an error for all pending calls to StartNotifySession. | |
79 while (!pending_start_notify_calls_.empty()) { | |
80 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front(); | |
81 pending_start_notify_calls_.pop(); | |
82 callbacks.second.Run(device::BluetoothRemoteGattService::GATT_ERROR_FAILED); | |
83 } | |
84 } | |
85 | |
86 void BluetoothRemoteGattCharacteristicBlueZ::StopNotifySession( | |
87 device::BluetoothGattNotifySession* session, | |
88 const base::Closure& callback) { | |
89 VLOG(1) << __func__; | |
90 | |
91 if (num_notify_sessions_ > 1) { | |
92 DCHECK(!notify_call_pending_); | |
93 --num_notify_sessions_; | |
94 callback.Run(); | |
95 return; | |
96 } | |
97 | |
98 // Notifications may have stopped outside our control. If the characteristic | |
99 // is no longer notifying, return success. | |
100 if (!IsNotifying()) { | |
101 num_notify_sessions_ = 0; | |
102 callback.Run(); | |
103 return; | |
104 } | |
105 | |
106 if (notify_call_pending_ || num_notify_sessions_ == 0) { | |
107 callback.Run(); | |
108 return; | |
109 } | |
110 | |
111 DCHECK(num_notify_sessions_ == 1); | |
112 notify_call_pending_ = true; | |
113 bluez::BluezDBusManager::Get() | |
114 ->GetBluetoothGattCharacteristicClient() | |
115 ->StopNotify( | |
116 object_path(), | |
117 base::Bind( | |
118 &BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifySuccess, | |
119 weak_ptr_factory_.GetWeakPtr(), callback), | |
120 base::Bind(&BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError, | |
121 weak_ptr_factory_.GetWeakPtr(), callback)); | |
122 } | 76 } |
123 | 77 |
124 device::BluetoothUUID BluetoothRemoteGattCharacteristicBlueZ::GetUUID() const { | 78 device::BluetoothUUID BluetoothRemoteGattCharacteristicBlueZ::GetUUID() const { |
125 bluez::BluetoothGattCharacteristicClient::Properties* properties = | 79 bluez::BluetoothGattCharacteristicClient::Properties* properties = |
126 bluez::BluezDBusManager::Get() | 80 bluez::BluezDBusManager::Get() |
127 ->GetBluetoothGattCharacteristicClient() | 81 ->GetBluetoothGattCharacteristicClient() |
128 ->GetProperties(object_path()); | 82 ->GetProperties(object_path()); |
129 DCHECK(properties); | 83 DCHECK(properties); |
130 return device::BluetoothUUID(properties->uuid.value()); | 84 return device::BluetoothUUID(properties->uuid.value()); |
131 } | 85 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 return service_; | 145 return service_; |
192 } | 146 } |
193 | 147 |
194 bool BluetoothRemoteGattCharacteristicBlueZ::IsNotifying() const { | 148 bool BluetoothRemoteGattCharacteristicBlueZ::IsNotifying() const { |
195 bluez::BluetoothGattCharacteristicClient::Properties* properties = | 149 bluez::BluetoothGattCharacteristicClient::Properties* properties = |
196 bluez::BluezDBusManager::Get() | 150 bluez::BluezDBusManager::Get() |
197 ->GetBluetoothGattCharacteristicClient() | 151 ->GetBluetoothGattCharacteristicClient() |
198 ->GetProperties(object_path()); | 152 ->GetProperties(object_path()); |
199 DCHECK(properties); | 153 DCHECK(properties); |
200 | 154 |
201 return properties->notifying.value(); | 155 // It is not enough to only check notifying.value(). Bluez also |
| 156 // needs a notify client/session in order to deliver the |
| 157 // notifications. |
| 158 return has_notify_session_ && properties->notifying.value(); |
202 } | 159 } |
203 | 160 |
204 std::vector<device::BluetoothRemoteGattDescriptor*> | 161 std::vector<device::BluetoothRemoteGattDescriptor*> |
205 BluetoothRemoteGattCharacteristicBlueZ::GetDescriptors() const { | 162 BluetoothRemoteGattCharacteristicBlueZ::GetDescriptors() const { |
206 std::vector<device::BluetoothRemoteGattDescriptor*> descriptors; | 163 std::vector<device::BluetoothRemoteGattDescriptor*> descriptors; |
207 for (DescriptorMap::const_iterator iter = descriptors_.begin(); | 164 for (DescriptorMap::const_iterator iter = descriptors_.begin(); |
208 iter != descriptors_.end(); ++iter) | 165 iter != descriptors_.end(); ++iter) |
209 descriptors.push_back(iter->second); | 166 descriptors.push_back(iter->second); |
210 return descriptors; | 167 return descriptors; |
211 } | 168 } |
212 | 169 |
213 device::BluetoothRemoteGattDescriptor* | 170 device::BluetoothRemoteGattDescriptor* |
214 BluetoothRemoteGattCharacteristicBlueZ::GetDescriptor( | 171 BluetoothRemoteGattCharacteristicBlueZ::GetDescriptor( |
215 const std::string& identifier) const { | 172 const std::string& identifier) const { |
216 DescriptorMap::const_iterator iter = | 173 DescriptorMap::const_iterator iter = |
217 descriptors_.find(dbus::ObjectPath(identifier)); | 174 descriptors_.find(dbus::ObjectPath(identifier)); |
218 if (iter == descriptors_.end()) | 175 if (iter == descriptors_.end()) |
219 return nullptr; | 176 return nullptr; |
220 return iter->second; | 177 return iter->second; |
221 } | 178 } |
222 | 179 |
223 void BluetoothRemoteGattCharacteristicBlueZ::StartNotifySession( | |
224 const NotifySessionCallback& callback, | |
225 const ErrorCallback& error_callback) { | |
226 VLOG(1) << __func__; | |
227 | |
228 if (num_notify_sessions_ > 0) { | |
229 // The characteristic might have stopped notifying even though the session | |
230 // count is nonzero. This means that notifications stopped outside of our | |
231 // control and we should reset the count. If the characteristic is still | |
232 // notifying, then return success. Otherwise, reset the count and treat | |
233 // this call as if the count were 0. | |
234 if (IsNotifying()) { | |
235 // Check for overflows, though unlikely. | |
236 if (num_notify_sessions_ == std::numeric_limits<size_t>::max()) { | |
237 error_callback.Run( | |
238 device::BluetoothRemoteGattService::GATT_ERROR_FAILED); | |
239 return; | |
240 } | |
241 | |
242 ++num_notify_sessions_; | |
243 DCHECK(service_); | |
244 DCHECK(service_->GetAdapter()); | |
245 DCHECK(service_->GetDevice()); | |
246 std::unique_ptr<device::BluetoothGattNotifySession> session( | |
247 new device::BluetoothGattNotifySession( | |
248 weak_ptr_factory_.GetWeakPtr())); | |
249 callback.Run(std::move(session)); | |
250 return; | |
251 } | |
252 | |
253 num_notify_sessions_ = 0; | |
254 } | |
255 | |
256 // Queue the callbacks if there is a pending call to bluetoothd. | |
257 if (notify_call_pending_) { | |
258 pending_start_notify_calls_.push(std::make_pair(callback, error_callback)); | |
259 return; | |
260 } | |
261 | |
262 notify_call_pending_ = true; | |
263 bluez::BluezDBusManager::Get() | |
264 ->GetBluetoothGattCharacteristicClient() | |
265 ->StartNotify( | |
266 object_path(), | |
267 base::Bind( | |
268 &BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifySuccess, | |
269 weak_ptr_factory_.GetWeakPtr(), callback), | |
270 base::Bind( | |
271 &BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifyError, | |
272 weak_ptr_factory_.GetWeakPtr(), error_callback)); | |
273 } | |
274 | |
275 void BluetoothRemoteGattCharacteristicBlueZ::ReadRemoteCharacteristic( | 180 void BluetoothRemoteGattCharacteristicBlueZ::ReadRemoteCharacteristic( |
276 const ValueCallback& callback, | 181 const ValueCallback& callback, |
277 const ErrorCallback& error_callback) { | 182 const ErrorCallback& error_callback) { |
278 VLOG(1) << "Sending GATT characteristic read request to characteristic: " | 183 VLOG(1) << "Sending GATT characteristic read request to characteristic: " |
279 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value() | 184 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value() |
280 << "."; | 185 << "."; |
281 | 186 |
282 bluez::BluezDBusManager::Get() | 187 bluez::BluezDBusManager::Get() |
283 ->GetBluetoothGattCharacteristicClient() | 188 ->GetBluetoothGattCharacteristicClient() |
284 ->ReadValue(object_path(), callback, | 189 ->ReadValue(object_path(), callback, |
(...skipping 13 matching lines...) Expand all Loading... |
298 ->GetBluetoothGattCharacteristicClient() | 203 ->GetBluetoothGattCharacteristicClient() |
299 ->WriteValue(object_path(), value, callback, | 204 ->WriteValue(object_path(), value, callback, |
300 base::Bind(&BluetoothRemoteGattCharacteristicBlueZ::OnError, | 205 base::Bind(&BluetoothRemoteGattCharacteristicBlueZ::OnError, |
301 weak_ptr_factory_.GetWeakPtr(), error_callback)); | 206 weak_ptr_factory_.GetWeakPtr(), error_callback)); |
302 } | 207 } |
303 | 208 |
304 void BluetoothRemoteGattCharacteristicBlueZ::SubscribeToNotifications( | 209 void BluetoothRemoteGattCharacteristicBlueZ::SubscribeToNotifications( |
305 device::BluetoothRemoteGattDescriptor* ccc_descriptor, | 210 device::BluetoothRemoteGattDescriptor* ccc_descriptor, |
306 const base::Closure& callback, | 211 const base::Closure& callback, |
307 const ErrorCallback& error_callback) { | 212 const ErrorCallback& error_callback) { |
308 // TODO(http://crbug.com/636275): Implement this method | 213 bluez::BluezDBusManager::Get() |
309 NOTIMPLEMENTED(); | 214 ->GetBluetoothGattCharacteristicClient() |
| 215 ->StartNotify( |
| 216 object_path(), |
| 217 base::Bind( |
| 218 &BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifySuccess, |
| 219 weak_ptr_factory_.GetWeakPtr(), callback), |
| 220 base::Bind( |
| 221 &BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifyError, |
| 222 weak_ptr_factory_.GetWeakPtr(), error_callback)); |
310 } | 223 } |
311 | 224 |
312 void BluetoothRemoteGattCharacteristicBlueZ::UnsubscribeFromNotifications( | 225 void BluetoothRemoteGattCharacteristicBlueZ::UnsubscribeFromNotifications( |
313 device::BluetoothRemoteGattDescriptor* ccc_descriptor, | 226 device::BluetoothRemoteGattDescriptor* ccc_descriptor, |
314 const base::Closure& callback, | 227 const base::Closure& callback, |
315 const ErrorCallback& error_callback) { | 228 const ErrorCallback& error_callback) { |
316 // TODO(http://crbug.com/636275): Implement this method | 229 bluez::BluezDBusManager::Get() |
317 NOTIMPLEMENTED(); | 230 ->GetBluetoothGattCharacteristicClient() |
| 231 ->StopNotify( |
| 232 object_path(), |
| 233 base::Bind( |
| 234 &BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifySuccess, |
| 235 weak_ptr_factory_.GetWeakPtr(), callback), |
| 236 base::Bind(&BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError, |
| 237 weak_ptr_factory_.GetWeakPtr(), callback)); |
318 } | 238 } |
319 | 239 |
320 void BluetoothRemoteGattCharacteristicBlueZ::GattDescriptorAdded( | 240 void BluetoothRemoteGattCharacteristicBlueZ::GattDescriptorAdded( |
321 const dbus::ObjectPath& object_path) { | 241 const dbus::ObjectPath& object_path) { |
322 if (descriptors_.find(object_path) != descriptors_.end()) { | 242 if (descriptors_.find(object_path) != descriptors_.end()) { |
323 VLOG(1) << "Remote GATT characteristic descriptor already exists: " | 243 VLOG(1) << "Remote GATT characteristic descriptor already exists: " |
324 << object_path.value(); | 244 << object_path.value(); |
325 return; | 245 return; |
326 } | 246 } |
327 | 247 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 if (property_name != properties->value.name()) | 310 if (property_name != properties->value.name()) |
391 return; | 311 return; |
392 | 312 |
393 DCHECK(service_); | 313 DCHECK(service_); |
394 static_cast<BluetoothRemoteGattServiceBlueZ*>(service_) | 314 static_cast<BluetoothRemoteGattServiceBlueZ*>(service_) |
395 ->NotifyDescriptorValueChanged(this, iter->second, | 315 ->NotifyDescriptorValueChanged(this, iter->second, |
396 properties->value.value()); | 316 properties->value.value()); |
397 } | 317 } |
398 | 318 |
399 void BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifySuccess( | 319 void BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifySuccess( |
400 const NotifySessionCallback& callback) { | 320 const base::Closure& callback) { |
401 VLOG(1) << "Started notifications from characteristic: " | 321 VLOG(1) << "Started notifications from characteristic: " |
402 << object_path().value(); | 322 << object_path().value(); |
403 DCHECK(num_notify_sessions_ == 0); | 323 has_notify_session_ = true; |
404 DCHECK(notify_call_pending_); | 324 callback.Run(); |
405 | |
406 ++num_notify_sessions_; | |
407 notify_call_pending_ = false; | |
408 | |
409 // Invoke the queued callbacks for this operation. | |
410 DCHECK(service_); | |
411 DCHECK(service_->GetDevice()); | |
412 std::unique_ptr<device::BluetoothGattNotifySession> session( | |
413 new device::BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr())); | |
414 callback.Run(std::move(session)); | |
415 | |
416 ProcessStartNotifyQueue(); | |
417 } | 325 } |
418 | 326 |
419 void BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifyError( | 327 void BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifyError( |
420 const ErrorCallback& error_callback, | 328 const ErrorCallback& error_callback, |
421 const std::string& error_name, | 329 const std::string& error_name, |
422 const std::string& error_message) { | 330 const std::string& error_message) { |
423 VLOG(1) << "Failed to start notifications from characteristic: " | 331 VLOG(1) << "Failed to start notifications from characteristic: " |
424 << object_path().value() << ": " << error_name << ", " | 332 << object_path().value() << ": " << error_name << ", " |
425 << error_message; | 333 << error_message; |
426 DCHECK(num_notify_sessions_ == 0); | |
427 DCHECK(notify_call_pending_); | |
428 | |
429 notify_call_pending_ = false; | |
430 | |
431 error_callback.Run( | 334 error_callback.Run( |
432 BluetoothRemoteGattServiceBlueZ::DBusErrorToServiceError(error_name)); | 335 BluetoothRemoteGattServiceBlueZ::DBusErrorToServiceError(error_name)); |
433 | |
434 ProcessStartNotifyQueue(); | |
435 } | 336 } |
436 | 337 |
437 void BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifySuccess( | 338 void BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifySuccess( |
438 const base::Closure& callback) { | 339 const base::Closure& callback) { |
439 DCHECK(notify_call_pending_); | 340 has_notify_session_ = false; |
440 DCHECK(num_notify_sessions_ == 1); | |
441 | |
442 notify_call_pending_ = false; | |
443 --num_notify_sessions_; | |
444 callback.Run(); | 341 callback.Run(); |
445 | |
446 ProcessStartNotifyQueue(); | |
447 } | 342 } |
448 | 343 |
449 void BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError( | 344 void BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError( |
450 const base::Closure& callback, | 345 const base::Closure& callback, |
451 const std::string& error_name, | 346 const std::string& error_name, |
452 const std::string& error_message) { | 347 const std::string& error_message) { |
453 VLOG(1) << "Call to stop notifications failed for characteristic: " | 348 VLOG(1) << "Call to stop notifications failed for characteristic: " |
454 << object_path().value() << ": " << error_name << ", " | 349 << object_path().value() << ": " << error_name << ", " |
455 << error_message; | 350 << error_message; |
456 | 351 |
457 // Since this is a best effort operation, treat this as success. | 352 // Since this is a best effort operation, treat this as success. |
458 OnStopNotifySuccess(callback); | 353 OnStopNotifySuccess(callback); |
459 } | 354 } |
460 | 355 |
461 void BluetoothRemoteGattCharacteristicBlueZ::ProcessStartNotifyQueue() { | |
462 while (!pending_start_notify_calls_.empty()) { | |
463 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front(); | |
464 pending_start_notify_calls_.pop(); | |
465 StartNotifySession(callbacks.first, callbacks.second); | |
466 } | |
467 } | |
468 | |
469 void BluetoothRemoteGattCharacteristicBlueZ::OnError( | 356 void BluetoothRemoteGattCharacteristicBlueZ::OnError( |
470 const ErrorCallback& error_callback, | 357 const ErrorCallback& error_callback, |
471 const std::string& error_name, | 358 const std::string& error_name, |
472 const std::string& error_message) { | 359 const std::string& error_message) { |
473 VLOG(1) << "Operation failed: " << error_name | 360 VLOG(1) << "Operation failed: " << error_name |
474 << ", message: " << error_message; | 361 << ", message: " << error_message; |
475 error_callback.Run( | 362 error_callback.Run( |
476 BluetoothGattServiceBlueZ::DBusErrorToServiceError(error_name)); | 363 BluetoothGattServiceBlueZ::DBusErrorToServiceError(error_name)); |
477 } | 364 } |
478 | 365 |
479 } // namespace bluez | 366 } // namespace bluez |
OLD | NEW |