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

Side by Side Diff: device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.cc

Issue 1415573014: Reland "Add Linux support for the Bluetooth API" (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: build fix. Created 5 years, 1 month 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 2014 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 "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
6
7 #include <limits>
8
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
12 #include "device/bluetooth/bluetooth_device.h"
13 #include "device/bluetooth/bluetooth_gatt_notify_session_chromeos.h"
14 #include "device/bluetooth/bluetooth_remote_gatt_characteristic_chromeos.h"
15 #include "device/bluetooth/bluetooth_remote_gatt_descriptor_chromeos.h"
16 #include "device/bluetooth/bluetooth_remote_gatt_service_chromeos.h"
17 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
19
20 namespace chromeos {
21
22 namespace {
23
24 // Stream operator for logging vector<uint8>.
25 std::ostream& operator<<(std::ostream& out, const std::vector<uint8> bytes) {
26 out << "[";
27 for (std::vector<uint8>::const_iterator iter = bytes.begin();
28 iter != bytes.end(); ++iter) {
29 out << base::StringPrintf("%02X", *iter);
30 }
31 return out << "]";
32 }
33
34 } // namespace
35
36 BluetoothRemoteGattCharacteristicChromeOS::
37 BluetoothRemoteGattCharacteristicChromeOS(
38 BluetoothRemoteGattServiceChromeOS* service,
39 const dbus::ObjectPath& object_path)
40 : object_path_(object_path),
41 service_(service),
42 num_notify_sessions_(0),
43 notify_call_pending_(false),
44 weak_ptr_factory_(this) {
45 VLOG(1) << "Creating remote GATT characteristic with identifier: "
46 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
47 bluez::BluezDBusManager::Get()
48 ->GetBluetoothGattDescriptorClient()
49 ->AddObserver(this);
50
51 // Add all known GATT characteristic descriptors.
52 const std::vector<dbus::ObjectPath>& gatt_descs =
53 bluez::BluezDBusManager::Get()
54 ->GetBluetoothGattDescriptorClient()
55 ->GetDescriptors();
56 for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin();
57 iter != gatt_descs.end(); ++iter)
58 GattDescriptorAdded(*iter);
59 }
60
61 BluetoothRemoteGattCharacteristicChromeOS::
62 ~BluetoothRemoteGattCharacteristicChromeOS() {
63 bluez::BluezDBusManager::Get()
64 ->GetBluetoothGattDescriptorClient()
65 ->RemoveObserver(this);
66
67 // Clean up all the descriptors. There isn't much point in notifying service
68 // observers for each descriptor that gets removed, so just delete them.
69 for (DescriptorMap::iterator iter = descriptors_.begin();
70 iter != descriptors_.end(); ++iter)
71 delete iter->second;
72
73 // Report an error for all pending calls to StartNotifySession.
74 while (!pending_start_notify_calls_.empty()) {
75 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front();
76 pending_start_notify_calls_.pop();
77 callbacks.second.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
78 }
79 }
80
81 std::string BluetoothRemoteGattCharacteristicChromeOS::GetIdentifier() const {
82 return object_path_.value();
83 }
84
85 device::BluetoothUUID
86 BluetoothRemoteGattCharacteristicChromeOS::GetUUID() const {
87 bluez::BluetoothGattCharacteristicClient::Properties* properties =
88 bluez::BluezDBusManager::Get()
89 ->GetBluetoothGattCharacteristicClient()
90 ->GetProperties(object_path_);
91 DCHECK(properties);
92 return device::BluetoothUUID(properties->uuid.value());
93 }
94
95 bool BluetoothRemoteGattCharacteristicChromeOS::IsLocal() const {
96 return false;
97 }
98
99 const std::vector<uint8>&
100 BluetoothRemoteGattCharacteristicChromeOS::GetValue() const {
101 bluez::BluetoothGattCharacteristicClient::Properties* properties =
102 bluez::BluezDBusManager::Get()
103 ->GetBluetoothGattCharacteristicClient()
104 ->GetProperties(object_path_);
105
106 DCHECK(properties);
107
108 return properties->value.value();
109 }
110
111 device::BluetoothGattService*
112 BluetoothRemoteGattCharacteristicChromeOS::GetService() const {
113 return service_;
114 }
115
116 device::BluetoothGattCharacteristic::Properties
117 BluetoothRemoteGattCharacteristicChromeOS::GetProperties() const {
118 bluez::BluetoothGattCharacteristicClient::Properties* properties =
119 bluez::BluezDBusManager::Get()
120 ->GetBluetoothGattCharacteristicClient()
121 ->GetProperties(object_path_);
122 DCHECK(properties);
123
124 Properties props = PROPERTY_NONE;
125 const std::vector<std::string>& flags = properties->flags.value();
126 for (std::vector<std::string>::const_iterator iter = flags.begin();
127 iter != flags.end();
128 ++iter) {
129 if (*iter == bluetooth_gatt_characteristic::kFlagBroadcast)
130 props |= PROPERTY_BROADCAST;
131 if (*iter == bluetooth_gatt_characteristic::kFlagRead)
132 props |= PROPERTY_READ;
133 if (*iter == bluetooth_gatt_characteristic::kFlagWriteWithoutResponse)
134 props |= PROPERTY_WRITE_WITHOUT_RESPONSE;
135 if (*iter == bluetooth_gatt_characteristic::kFlagWrite)
136 props |= PROPERTY_WRITE;
137 if (*iter == bluetooth_gatt_characteristic::kFlagNotify)
138 props |= PROPERTY_NOTIFY;
139 if (*iter == bluetooth_gatt_characteristic::kFlagIndicate)
140 props |= PROPERTY_INDICATE;
141 if (*iter == bluetooth_gatt_characteristic::kFlagAuthenticatedSignedWrites)
142 props |= PROPERTY_AUTHENTICATED_SIGNED_WRITES;
143 if (*iter == bluetooth_gatt_characteristic::kFlagExtendedProperties)
144 props |= PROPERTY_EXTENDED_PROPERTIES;
145 if (*iter == bluetooth_gatt_characteristic::kFlagReliableWrite)
146 props |= PROPERTY_RELIABLE_WRITE;
147 if (*iter == bluetooth_gatt_characteristic::kFlagWritableAuxiliaries)
148 props |= PROPERTY_WRITABLE_AUXILIARIES;
149 }
150
151 return props;
152 }
153
154 device::BluetoothGattCharacteristic::Permissions
155 BluetoothRemoteGattCharacteristicChromeOS::GetPermissions() const {
156 // TODO(armansito): Once BlueZ defines the permissions, return the correct
157 // values here.
158 return PERMISSION_NONE;
159 }
160
161 bool BluetoothRemoteGattCharacteristicChromeOS::IsNotifying() const {
162 bluez::BluetoothGattCharacteristicClient::Properties* properties =
163 bluez::BluezDBusManager::Get()
164 ->GetBluetoothGattCharacteristicClient()
165 ->GetProperties(object_path_);
166 DCHECK(properties);
167
168 return properties->notifying.value();
169 }
170
171 std::vector<device::BluetoothGattDescriptor*>
172 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptors() const {
173 std::vector<device::BluetoothGattDescriptor*> descriptors;
174 for (DescriptorMap::const_iterator iter = descriptors_.begin();
175 iter != descriptors_.end(); ++iter)
176 descriptors.push_back(iter->second);
177 return descriptors;
178 }
179
180 device::BluetoothGattDescriptor*
181 BluetoothRemoteGattCharacteristicChromeOS::GetDescriptor(
182 const std::string& identifier) const {
183 DescriptorMap::const_iterator iter =
184 descriptors_.find(dbus::ObjectPath(identifier));
185 if (iter == descriptors_.end())
186 return NULL;
187 return iter->second;
188 }
189
190 bool BluetoothRemoteGattCharacteristicChromeOS::AddDescriptor(
191 device::BluetoothGattDescriptor* descriptor) {
192 VLOG(1) << "Descriptors cannot be added to a remote GATT characteristic.";
193 return false;
194 }
195
196 bool BluetoothRemoteGattCharacteristicChromeOS::UpdateValue(
197 const std::vector<uint8>& value) {
198 VLOG(1) << "Cannot update the value of a remote GATT characteristic.";
199 return false;
200 }
201
202 void BluetoothRemoteGattCharacteristicChromeOS::ReadRemoteCharacteristic(
203 const ValueCallback& callback,
204 const ErrorCallback& error_callback) {
205 VLOG(1) << "Sending GATT characteristic read request to characteristic: "
206 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value()
207 << ".";
208
209 bluez::BluezDBusManager::Get()
210 ->GetBluetoothGattCharacteristicClient()
211 ->ReadValue(
212 object_path_, callback,
213 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError,
214 weak_ptr_factory_.GetWeakPtr(), error_callback));
215 }
216
217 void BluetoothRemoteGattCharacteristicChromeOS::WriteRemoteCharacteristic(
218 const std::vector<uint8>& new_value,
219 const base::Closure& callback,
220 const ErrorCallback& error_callback) {
221 VLOG(1) << "Sending GATT characteristic write request to characteristic: "
222 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value()
223 << ", with value: " << new_value << ".";
224
225 bluez::BluezDBusManager::Get()
226 ->GetBluetoothGattCharacteristicClient()
227 ->WriteValue(
228 object_path_, new_value, callback,
229 base::Bind(&BluetoothRemoteGattCharacteristicChromeOS::OnError,
230 weak_ptr_factory_.GetWeakPtr(), error_callback));
231 }
232
233 void BluetoothRemoteGattCharacteristicChromeOS::StartNotifySession(
234 const NotifySessionCallback& callback,
235 const ErrorCallback& error_callback) {
236 VLOG(1) << __func__;
237
238 if (num_notify_sessions_ > 0) {
239 // The characteristic might have stopped notifying even though the session
240 // count is nonzero. This means that notifications stopped outside of our
241 // control and we should reset the count. If the characteristic is still
242 // notifying, then return success. Otherwise, reset the count and treat
243 // this call as if the count were 0.
244 if (IsNotifying()) {
245 // Check for overflows, though unlikely.
246 if (num_notify_sessions_ == std::numeric_limits<size_t>::max()) {
247 error_callback.Run(device::BluetoothGattService::GATT_ERROR_FAILED);
248 return;
249 }
250
251 ++num_notify_sessions_;
252 DCHECK(service_);
253 DCHECK(service_->GetAdapter());
254 DCHECK(service_->GetDevice());
255 scoped_ptr<device::BluetoothGattNotifySession> session(
256 new BluetoothGattNotifySessionChromeOS(
257 service_->GetAdapter(),
258 service_->GetDevice()->GetAddress(),
259 service_->GetIdentifier(),
260 GetIdentifier(),
261 object_path_));
262 callback.Run(session.Pass());
263 return;
264 }
265
266 num_notify_sessions_ = 0;
267 }
268
269 // Queue the callbacks if there is a pending call to bluetoothd.
270 if (notify_call_pending_) {
271 pending_start_notify_calls_.push(std::make_pair(callback, error_callback));
272 return;
273 }
274
275 notify_call_pending_ = true;
276 bluez::BluezDBusManager::Get()
277 ->GetBluetoothGattCharacteristicClient()
278 ->StartNotify(
279 object_path_,
280 base::Bind(
281 &BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess,
282 weak_ptr_factory_.GetWeakPtr(), callback),
283 base::Bind(
284 &BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError,
285 weak_ptr_factory_.GetWeakPtr(), error_callback));
286 }
287
288 void BluetoothRemoteGattCharacteristicChromeOS::RemoveNotifySession(
289 const base::Closure& callback) {
290 VLOG(1) << __func__;
291
292 if (num_notify_sessions_ > 1) {
293 DCHECK(!notify_call_pending_);
294 --num_notify_sessions_;
295 callback.Run();
296 return;
297 }
298
299 // Notifications may have stopped outside our control. If the characteristic
300 // is no longer notifying, return success.
301 if (!IsNotifying()) {
302 num_notify_sessions_ = 0;
303 callback.Run();
304 return;
305 }
306
307 if (notify_call_pending_ || num_notify_sessions_ == 0) {
308 callback.Run();
309 return;
310 }
311
312 DCHECK(num_notify_sessions_ == 1);
313 notify_call_pending_ = true;
314 bluez::BluezDBusManager::Get()
315 ->GetBluetoothGattCharacteristicClient()
316 ->StopNotify(
317 object_path_,
318 base::Bind(
319 &BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess,
320 weak_ptr_factory_.GetWeakPtr(), callback),
321 base::Bind(
322 &BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError,
323 weak_ptr_factory_.GetWeakPtr(), callback));
324 }
325
326 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorAdded(
327 const dbus::ObjectPath& object_path) {
328 if (descriptors_.find(object_path) != descriptors_.end()) {
329 VLOG(1) << "Remote GATT characteristic descriptor already exists: "
330 << object_path.value();
331 return;
332 }
333
334 bluez::BluetoothGattDescriptorClient::Properties* properties =
335 bluez::BluezDBusManager::Get()
336 ->GetBluetoothGattDescriptorClient()
337 ->GetProperties(object_path);
338 DCHECK(properties);
339 if (properties->characteristic.value() != object_path_) {
340 VLOG(3) << "Remote GATT descriptor does not belong to this characteristic.";
341 return;
342 }
343
344 VLOG(1) << "Adding new remote GATT descriptor for GATT characteristic: "
345 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
346
347 BluetoothRemoteGattDescriptorChromeOS* descriptor =
348 new BluetoothRemoteGattDescriptorChromeOS(this, object_path);
349 descriptors_[object_path] = descriptor;
350 DCHECK(descriptor->GetIdentifier() == object_path.value());
351 DCHECK(descriptor->GetUUID().IsValid());
352 DCHECK(service_);
353
354 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, true /* added */);
355 }
356
357 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorRemoved(
358 const dbus::ObjectPath& object_path) {
359 DescriptorMap::iterator iter = descriptors_.find(object_path);
360 if (iter == descriptors_.end()) {
361 VLOG(2) << "Unknown descriptor removed: " << object_path.value();
362 return;
363 }
364
365 VLOG(1) << "Removing remote GATT descriptor from characteristic: "
366 << GetIdentifier() << ", UUID: " << GetUUID().canonical_value();
367
368 BluetoothRemoteGattDescriptorChromeOS* descriptor = iter->second;
369 DCHECK(descriptor->object_path() == object_path);
370 descriptors_.erase(iter);
371
372 DCHECK(service_);
373 service_->NotifyDescriptorAddedOrRemoved(this, descriptor, false /* added */);
374
375 delete descriptor;
376 }
377
378 void BluetoothRemoteGattCharacteristicChromeOS::GattDescriptorPropertyChanged(
379 const dbus::ObjectPath& object_path,
380 const std::string& property_name) {
381 DescriptorMap::iterator iter = descriptors_.find(object_path);
382 if (iter == descriptors_.end()) {
383 VLOG(2) << "Unknown descriptor removed: " << object_path.value();
384 return;
385 }
386
387 bluez::BluetoothGattDescriptorClient::Properties* properties =
388 bluez::BluezDBusManager::Get()
389 ->GetBluetoothGattDescriptorClient()
390 ->GetProperties(object_path);
391
392 DCHECK(properties);
393
394 if (property_name != properties->value.name())
395 return;
396
397 DCHECK(service_);
398 service_->NotifyDescriptorValueChanged(this, iter->second,
399 properties->value.value());
400 }
401
402 void BluetoothRemoteGattCharacteristicChromeOS::OnError(
403 const ErrorCallback& error_callback,
404 const std::string& error_name,
405 const std::string& error_message) {
406 VLOG(1) << "Operation failed: " << error_name << ", message: "
407 << error_message;
408 error_callback.Run(
409 BluetoothRemoteGattServiceChromeOS::DBusErrorToServiceError(error_name));
410 }
411
412 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifySuccess(
413 const NotifySessionCallback& callback) {
414 VLOG(1) << "Started notifications from characteristic: "
415 << object_path_.value();
416 DCHECK(num_notify_sessions_ == 0);
417 DCHECK(notify_call_pending_);
418
419 ++num_notify_sessions_;
420 notify_call_pending_ = false;
421
422 // Invoke the queued callbacks for this operation.
423 DCHECK(service_);
424 DCHECK(service_->GetDevice());
425 scoped_ptr<device::BluetoothGattNotifySession> session(
426 new BluetoothGattNotifySessionChromeOS(
427 service_->GetAdapter(),
428 service_->GetDevice()->GetAddress(),
429 service_->GetIdentifier(),
430 GetIdentifier(),
431 object_path_));
432 callback.Run(session.Pass());
433
434 ProcessStartNotifyQueue();
435 }
436
437 void BluetoothRemoteGattCharacteristicChromeOS::OnStartNotifyError(
438 const ErrorCallback& error_callback,
439 const std::string& error_name,
440 const std::string& error_message) {
441 VLOG(1) << "Failed to start notifications from characteristic: "
442 << object_path_.value() << ": " << error_name << ", "
443 << error_message;
444 DCHECK(num_notify_sessions_ == 0);
445 DCHECK(notify_call_pending_);
446
447 notify_call_pending_ = false;
448
449 error_callback.Run(
450 BluetoothRemoteGattServiceChromeOS::DBusErrorToServiceError(error_name));
451
452 ProcessStartNotifyQueue();
453 }
454
455 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifySuccess(
456 const base::Closure& callback) {
457 DCHECK(notify_call_pending_);
458 DCHECK(num_notify_sessions_ == 1);
459
460 notify_call_pending_ = false;
461 --num_notify_sessions_;
462 callback.Run();
463
464 ProcessStartNotifyQueue();
465 }
466
467 void BluetoothRemoteGattCharacteristicChromeOS::OnStopNotifyError(
468 const base::Closure& callback,
469 const std::string& error_name,
470 const std::string& error_message) {
471 VLOG(1) << "Call to stop notifications failed for characteristic: "
472 << object_path_.value() << ": " << error_name << ", "
473 << error_message;
474
475 // Since this is a best effort operation, treat this as success.
476 OnStopNotifySuccess(callback);
477 }
478
479 void BluetoothRemoteGattCharacteristicChromeOS::ProcessStartNotifyQueue() {
480 while (!pending_start_notify_calls_.empty()) {
481 PendingStartNotifyCall callbacks = pending_start_notify_calls_.front();
482 pending_start_notify_calls_.pop();
483 StartNotifySession(callbacks.first, callbacks.second);
484 }
485 }
486
487 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698