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

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

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

Powered by Google App Engine
This is Rietveld 408576698