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

Side by Side Diff: device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc

Issue 2613473002: bluetooth: bluez: Implement BluetoothRemoteGattCharacteristicBluez::SubscribeToNotifications and Un… (Closed)
Patch Set: Also include Chrome OS as it uses Bluez. Created 3 years, 11 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
« no previous file with comments | « device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698