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

Side by Side Diff: device/bluetooth/bluetooth_socket_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 2013 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_socket_bluez.h"
6
7 #include <stdint.h>
8
9 #include <memory>
10 #include <queue>
11 #include <string>
12 #include <utility>
13
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/logging.h"
17 #include "base/memory/linked_ptr.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/sequenced_task_runner.h"
21 #include "base/strings/string_util.h"
22 #include "base/task_runner_util.h"
23 #include "base/threading/thread_restrictions.h"
24 #include "base/threading/worker_pool.h"
25 #include "dbus/bus.h"
26 #include "dbus/file_descriptor.h"
27 #include "dbus/object_path.h"
28 #include "device/bluetooth/bluetooth_adapter.h"
29 #include "device/bluetooth/bluetooth_adapter_bluez.h"
30 #include "device/bluetooth/bluetooth_adapter_profile_bluez.h"
31 #include "device/bluetooth/bluetooth_device.h"
32 #include "device/bluetooth/bluetooth_device_bluez.h"
33 #include "device/bluetooth/bluetooth_socket.h"
34 #include "device/bluetooth/bluetooth_socket_net.h"
35 #include "device/bluetooth/bluetooth_socket_thread.h"
36 #include "device/bluetooth/dbus/bluetooth_device_client.h"
37 #include "device/bluetooth/dbus/bluetooth_profile_manager_client.h"
38 #include "device/bluetooth/dbus/bluetooth_profile_service_provider.h"
39 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
40 #include "net/base/ip_endpoint.h"
41 #include "net/base/net_errors.h"
42 #include "third_party/cros_system_api/dbus/service_constants.h"
43
44 using device::BluetoothAdapter;
45 using device::BluetoothDevice;
46 using device::BluetoothSocketThread;
47 using device::BluetoothUUID;
48
49 namespace {
50
51 const char kAcceptFailed[] = "Failed to accept connection.";
52 const char kInvalidUUID[] = "Invalid UUID";
53 const char kSocketNotListening[] = "Socket is not listening.";
54
55 } // namespace
56
57 namespace bluez {
58
59 // static
60 scoped_refptr<BluetoothSocketBlueZ> BluetoothSocketBlueZ::CreateBluetoothSocket(
61 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
62 scoped_refptr<BluetoothSocketThread> socket_thread) {
63 DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
64
65 return make_scoped_refptr(
66 new BluetoothSocketBlueZ(ui_task_runner, socket_thread));
67 }
68
69 BluetoothSocketBlueZ::AcceptRequest::AcceptRequest() {}
70
71 BluetoothSocketBlueZ::AcceptRequest::~AcceptRequest() {}
72
73 BluetoothSocketBlueZ::ConnectionRequest::ConnectionRequest()
74 : accepting(false), cancelled(false) {}
75
76 BluetoothSocketBlueZ::ConnectionRequest::~ConnectionRequest() {}
77
78 BluetoothSocketBlueZ::BluetoothSocketBlueZ(
79 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
80 scoped_refptr<BluetoothSocketThread> socket_thread)
81 : BluetoothSocketNet(ui_task_runner, socket_thread), profile_(nullptr) {}
82
83 BluetoothSocketBlueZ::~BluetoothSocketBlueZ() {
84 DCHECK(!profile_);
85
86 if (adapter_.get()) {
87 adapter_->RemoveObserver(this);
88 adapter_ = nullptr;
89 }
90 }
91
92 void BluetoothSocketBlueZ::Connect(
93 const BluetoothDeviceBlueZ* device,
94 const BluetoothUUID& uuid,
95 SecurityLevel security_level,
96 const base::Closure& success_callback,
97 const ErrorCompletionCallback& error_callback) {
98 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
99 DCHECK(!profile_);
100
101 if (!uuid.IsValid()) {
102 error_callback.Run(kInvalidUUID);
103 return;
104 }
105
106 device_address_ = device->GetAddress();
107 device_path_ = device->object_path();
108 uuid_ = uuid;
109 options_.reset(new bluez::BluetoothProfileManagerClient::Options());
110 if (security_level == SECURITY_LEVEL_LOW)
111 options_->require_authentication.reset(new bool(false));
112
113 adapter_ = device->adapter();
114
115 RegisterProfile(device->adapter(), success_callback, error_callback);
116 }
117
118 void BluetoothSocketBlueZ::Listen(
119 scoped_refptr<BluetoothAdapter> adapter,
120 SocketType socket_type,
121 const BluetoothUUID& uuid,
122 const BluetoothAdapter::ServiceOptions& service_options,
123 const base::Closure& success_callback,
124 const ErrorCompletionCallback& error_callback) {
125 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
126 DCHECK(!profile_);
127
128 if (!uuid.IsValid()) {
129 error_callback.Run(kInvalidUUID);
130 return;
131 }
132
133 adapter_ = adapter;
134 adapter_->AddObserver(this);
135
136 uuid_ = uuid;
137 options_.reset(new bluez::BluetoothProfileManagerClient::Options());
138 if (service_options.name)
139 options_->name.reset(new std::string(*service_options.name));
140
141 switch (socket_type) {
142 case kRfcomm:
143 options_->channel.reset(
144 new uint16_t(service_options.channel ? *service_options.channel : 0));
145 break;
146 case kL2cap:
147 options_->psm.reset(
148 new uint16_t(service_options.psm ? *service_options.psm : 0));
149 break;
150 default:
151 NOTREACHED();
152 }
153
154 RegisterProfile(static_cast<BluetoothAdapterBlueZ*>(adapter.get()),
155 success_callback, error_callback);
156 }
157
158 void BluetoothSocketBlueZ::Close() {
159 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
160
161 if (profile_)
162 UnregisterProfile();
163
164 // In the case below, where an asynchronous task gets posted on the socket
165 // thread in BluetoothSocketNet::Close, a reference will be held to this
166 // socket by the callback. This may cause the BluetoothAdapter to outlive
167 // BluezDBusManager during shutdown if that callback executes too late.
168 if (adapter_.get()) {
169 adapter_->RemoveObserver(this);
170 adapter_ = nullptr;
171 }
172
173 if (!device_path_.value().empty()) {
174 BluetoothSocketNet::Close();
175 } else {
176 DoCloseListening();
177 }
178 }
179
180 void BluetoothSocketBlueZ::Disconnect(const base::Closure& callback) {
181 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
182
183 if (profile_)
184 UnregisterProfile();
185
186 if (!device_path_.value().empty()) {
187 BluetoothSocketNet::Disconnect(callback);
188 } else {
189 DoCloseListening();
190 callback.Run();
191 }
192 }
193
194 void BluetoothSocketBlueZ::Accept(
195 const AcceptCompletionCallback& success_callback,
196 const ErrorCompletionCallback& error_callback) {
197 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
198
199 if (!device_path_.value().empty()) {
200 error_callback.Run(kSocketNotListening);
201 return;
202 }
203
204 // Only one pending accept at a time
205 if (accept_request_.get()) {
206 error_callback.Run(net::ErrorToString(net::ERR_IO_PENDING));
207 return;
208 }
209
210 accept_request_.reset(new AcceptRequest);
211 accept_request_->success_callback = success_callback;
212 accept_request_->error_callback = error_callback;
213
214 if (connection_request_queue_.size() >= 1) {
215 AcceptConnectionRequest();
216 }
217 }
218
219 void BluetoothSocketBlueZ::RegisterProfile(
220 BluetoothAdapterBlueZ* adapter,
221 const base::Closure& success_callback,
222 const ErrorCompletionCallback& error_callback) {
223 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
224 DCHECK(!profile_);
225 DCHECK(adapter);
226
227 // If the adapter is not present, this is a listening socket and the
228 // adapter isn't running yet. Report success and carry on;
229 // the profile will be registered when the daemon becomes available.
230 if (!adapter->IsPresent()) {
231 VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
232 << ": Delaying profile registration.";
233 base::MessageLoop::current()->PostTask(FROM_HERE, success_callback);
234 return;
235 }
236
237 VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
238 << ": Acquiring profile.";
239
240 adapter->UseProfile(uuid_, device_path_, *options_, this,
241 base::Bind(&BluetoothSocketBlueZ::OnRegisterProfile, this,
242 success_callback, error_callback),
243 base::Bind(&BluetoothSocketBlueZ::OnRegisterProfileError,
244 this, error_callback));
245 }
246
247 void BluetoothSocketBlueZ::OnRegisterProfile(
248 const base::Closure& success_callback,
249 const ErrorCompletionCallback& error_callback,
250 BluetoothAdapterProfileBlueZ* profile) {
251 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
252 DCHECK(!profile_);
253
254 profile_ = profile;
255
256 if (device_path_.value().empty()) {
257 VLOG(1) << uuid_.canonical_value() << ": Profile registered.";
258 success_callback.Run();
259 return;
260 }
261
262 VLOG(1) << uuid_.canonical_value() << ": Got profile, connecting to "
263 << device_path_.value();
264
265 bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
266 device_path_, uuid_.canonical_value(),
267 base::Bind(&BluetoothSocketBlueZ::OnConnectProfile, this,
268 success_callback),
269 base::Bind(&BluetoothSocketBlueZ::OnConnectProfileError, this,
270 error_callback));
271 }
272
273 void BluetoothSocketBlueZ::OnRegisterProfileError(
274 const ErrorCompletionCallback& error_callback,
275 const std::string& error_message) {
276 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
277
278 LOG(WARNING) << uuid_.canonical_value()
279 << ": Failed to register profile: " << error_message;
280 error_callback.Run(error_message);
281 }
282
283 void BluetoothSocketBlueZ::OnConnectProfile(
284 const base::Closure& success_callback) {
285 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
286 DCHECK(profile_);
287
288 VLOG(1) << profile_->object_path().value() << ": Profile connected.";
289 UnregisterProfile();
290 success_callback.Run();
291 }
292
293 void BluetoothSocketBlueZ::OnConnectProfileError(
294 const ErrorCompletionCallback& error_callback,
295 const std::string& error_name,
296 const std::string& error_message) {
297 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
298 DCHECK(profile_);
299
300 LOG(WARNING) << profile_->object_path().value()
301 << ": Failed to connect profile: " << error_name << ": "
302 << error_message;
303 UnregisterProfile();
304 error_callback.Run(error_message);
305 }
306
307 void BluetoothSocketBlueZ::AdapterPresentChanged(BluetoothAdapter* adapter,
308 bool present) {
309 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
310
311 if (!present) {
312 // Adapter removed, we can't use the profile anymore.
313 UnregisterProfile();
314 return;
315 }
316
317 DCHECK(!profile_);
318
319 VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
320 << ": Acquiring profile.";
321
322 static_cast<BluetoothAdapterBlueZ*>(adapter)->UseProfile(
323 uuid_, device_path_, *options_, this,
324 base::Bind(&BluetoothSocketBlueZ::OnInternalRegisterProfile, this),
325 base::Bind(&BluetoothSocketBlueZ::OnInternalRegisterProfileError, this));
326 }
327
328 void BluetoothSocketBlueZ::OnInternalRegisterProfile(
329 BluetoothAdapterProfileBlueZ* profile) {
330 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
331 DCHECK(!profile_);
332
333 profile_ = profile;
334
335 VLOG(1) << uuid_.canonical_value() << ": Profile re-registered";
336 }
337
338 void BluetoothSocketBlueZ::OnInternalRegisterProfileError(
339 const std::string& error_message) {
340 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
341
342 LOG(WARNING) << "Failed to re-register profile: " << error_message;
343 }
344
345 void BluetoothSocketBlueZ::Released() {
346 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
347 DCHECK(profile_);
348
349 VLOG(1) << profile_->object_path().value() << ": Release";
350 }
351
352 void BluetoothSocketBlueZ::NewConnection(
353 const dbus::ObjectPath& device_path,
354 std::unique_ptr<dbus::FileDescriptor> fd,
355 const bluez::BluetoothProfileServiceProvider::Delegate::Options& options,
356 const ConfirmationCallback& callback) {
357 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
358
359 VLOG(1) << uuid_.canonical_value()
360 << ": New connection from device: " << device_path.value();
361
362 if (!device_path_.value().empty()) {
363 DCHECK(device_path_ == device_path);
364
365 socket_thread()->task_runner()->PostTask(
366 FROM_HERE,
367 base::Bind(&BluetoothSocketBlueZ::DoNewConnection, this, device_path_,
368 base::Passed(&fd), options, callback));
369 } else {
370 linked_ptr<ConnectionRequest> request(new ConnectionRequest());
371 request->device_path = device_path;
372 request->fd = std::move(fd);
373 request->options = options;
374 request->callback = callback;
375
376 connection_request_queue_.push(request);
377 VLOG(1) << uuid_.canonical_value() << ": Connection is now pending.";
378 if (accept_request_) {
379 AcceptConnectionRequest();
380 }
381 }
382 }
383
384 void BluetoothSocketBlueZ::RequestDisconnection(
385 const dbus::ObjectPath& device_path,
386 const ConfirmationCallback& callback) {
387 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
388 DCHECK(profile_);
389
390 VLOG(1) << profile_->object_path().value() << ": Request disconnection";
391 callback.Run(SUCCESS);
392 }
393
394 void BluetoothSocketBlueZ::Cancel() {
395 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
396 DCHECK(profile_);
397
398 VLOG(1) << profile_->object_path().value() << ": Cancel";
399
400 if (!connection_request_queue_.size())
401 return;
402
403 // If the front request is being accepted mark it as cancelled, otherwise
404 // just pop it from the queue.
405 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
406 if (!request->accepting) {
407 request->cancelled = true;
408 } else {
409 connection_request_queue_.pop();
410 }
411 }
412
413 void BluetoothSocketBlueZ::AcceptConnectionRequest() {
414 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
415 DCHECK(accept_request_.get());
416 DCHECK(connection_request_queue_.size() >= 1);
417 DCHECK(profile_);
418
419 VLOG(1) << profile_->object_path().value()
420 << ": Accepting pending connection.";
421
422 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
423 request->accepting = true;
424
425 BluetoothDeviceBlueZ* device =
426 static_cast<BluetoothAdapterBlueZ*>(adapter_.get())
427 ->GetDeviceWithPath(request->device_path);
428 DCHECK(device);
429
430 scoped_refptr<BluetoothSocketBlueZ> client_socket =
431 BluetoothSocketBlueZ::CreateBluetoothSocket(ui_task_runner(),
432 socket_thread());
433
434 client_socket->device_address_ = device->GetAddress();
435 client_socket->device_path_ = request->device_path;
436 client_socket->uuid_ = uuid_;
437
438 socket_thread()->task_runner()->PostTask(
439 FROM_HERE,
440 base::Bind(&BluetoothSocketBlueZ::DoNewConnection, client_socket,
441 request->device_path, base::Passed(&request->fd),
442 request->options,
443 base::Bind(&BluetoothSocketBlueZ::OnNewConnection, this,
444 client_socket, request->callback)));
445 }
446
447 void BluetoothSocketBlueZ::DoNewConnection(
448 const dbus::ObjectPath& device_path,
449 std::unique_ptr<dbus::FileDescriptor> fd,
450 const bluez::BluetoothProfileServiceProvider::Delegate::Options& options,
451 const ConfirmationCallback& callback) {
452 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
453 base::ThreadRestrictions::AssertIOAllowed();
454 fd->CheckValidity();
455
456 VLOG(1) << uuid_.canonical_value() << ": Validity check complete.";
457 if (!fd->is_valid()) {
458 LOG(WARNING) << uuid_.canonical_value() << " :" << fd->value()
459 << ": Invalid file descriptor received from Bluetooth Daemon.";
460 ui_task_runner()->PostTask(FROM_HERE, base::Bind(callback, REJECTED));
461 return;
462 }
463
464 if (tcp_socket()) {
465 LOG(WARNING) << uuid_.canonical_value() << ": Already connected";
466 ui_task_runner()->PostTask(FROM_HERE, base::Bind(callback, REJECTED));
467 return;
468 }
469
470 ResetTCPSocket();
471
472 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
473 // TCPSocket implementation does not actually require one.
474 int net_result =
475 tcp_socket()->AdoptConnectedSocket(fd->value(), net::IPEndPoint());
476 if (net_result != net::OK) {
477 LOG(WARNING) << uuid_.canonical_value() << ": Error adopting socket: "
478 << std::string(net::ErrorToString(net_result));
479 ui_task_runner()->PostTask(FROM_HERE, base::Bind(callback, REJECTED));
480 return;
481 }
482
483 VLOG(2) << uuid_.canonical_value()
484 << ": Taking descriptor, confirming success.";
485 fd->TakeValue();
486 ui_task_runner()->PostTask(FROM_HERE, base::Bind(callback, SUCCESS));
487 }
488
489 void BluetoothSocketBlueZ::OnNewConnection(
490 scoped_refptr<BluetoothSocket> socket,
491 const ConfirmationCallback& callback,
492 Status status) {
493 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
494 DCHECK(accept_request_.get());
495 DCHECK(connection_request_queue_.size() >= 1);
496
497 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
498 if (status == SUCCESS && !request->cancelled) {
499 BluetoothDeviceBlueZ* device =
500 static_cast<BluetoothAdapterBlueZ*>(adapter_.get())
501 ->GetDeviceWithPath(request->device_path);
502 DCHECK(device);
503
504 accept_request_->success_callback.Run(device, socket);
505 } else {
506 accept_request_->error_callback.Run(kAcceptFailed);
507 }
508
509 accept_request_.reset(nullptr);
510 connection_request_queue_.pop();
511
512 callback.Run(status);
513 }
514
515 void BluetoothSocketBlueZ::DoCloseListening() {
516 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
517
518 if (accept_request_) {
519 accept_request_->error_callback.Run(
520 net::ErrorToString(net::ERR_CONNECTION_CLOSED));
521 accept_request_.reset(nullptr);
522 }
523
524 while (connection_request_queue_.size() > 0) {
525 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
526 request->callback.Run(REJECTED);
527 connection_request_queue_.pop();
528 }
529 }
530
531 void BluetoothSocketBlueZ::UnregisterProfile() {
532 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
533 DCHECK(profile_);
534
535 VLOG(1) << profile_->object_path().value() << ": Release profile";
536
537 static_cast<BluetoothAdapterBlueZ*>(adapter_.get())
538 ->ReleaseProfile(device_path_, profile_);
539 profile_ = nullptr;
540 }
541
542 } // namespace bluez
OLDNEW
« no previous file with comments | « device/bluetooth/bluetooth_socket_bluez.h ('k') | device/bluetooth/bluetooth_socket_bluez_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698