[Ozone-Gbm] Explicitly crash if trying software rendering on GBM
[chromium-blink-merge.git] / device / bluetooth / bluetooth_socket_chromeos.cc
blob3026113a5cb9a1de191b98e29b04759b29129b4e
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.
5 #include "device/bluetooth/bluetooth_socket_chromeos.h"
7 #include <queue>
8 #include <string>
10 #include "base/basictypes.h"
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/logging.h"
14 #include "base/memory/linked_ptr.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/task_runner_util.h"
20 #include "base/threading/thread_restrictions.h"
21 #include "base/threading/worker_pool.h"
22 #include "chromeos/dbus/bluetooth_device_client.h"
23 #include "chromeos/dbus/bluetooth_profile_manager_client.h"
24 #include "chromeos/dbus/bluetooth_profile_service_provider.h"
25 #include "chromeos/dbus/dbus_thread_manager.h"
26 #include "dbus/bus.h"
27 #include "dbus/file_descriptor.h"
28 #include "dbus/object_path.h"
29 #include "device/bluetooth/bluetooth_adapter.h"
30 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
31 #include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
32 #include "device/bluetooth/bluetooth_device.h"
33 #include "device/bluetooth/bluetooth_device_chromeos.h"
34 #include "device/bluetooth/bluetooth_socket.h"
35 #include "device/bluetooth/bluetooth_socket_net.h"
36 #include "device/bluetooth/bluetooth_socket_thread.h"
37 #include "net/base/ip_endpoint.h"
38 #include "net/base/net_errors.h"
39 #include "third_party/cros_system_api/dbus/service_constants.h"
41 using device::BluetoothAdapter;
42 using device::BluetoothDevice;
43 using device::BluetoothSocketThread;
44 using device::BluetoothUUID;
46 namespace {
48 const char kAcceptFailed[] = "Failed to accept connection.";
49 const char kInvalidUUID[] = "Invalid UUID";
50 const char kSocketNotListening[] = "Socket is not listening.";
52 } // namespace
54 namespace chromeos {
56 // static
57 scoped_refptr<BluetoothSocketChromeOS>
58 BluetoothSocketChromeOS::CreateBluetoothSocket(
59 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
60 scoped_refptr<BluetoothSocketThread> socket_thread) {
61 DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
63 return make_scoped_refptr(
64 new BluetoothSocketChromeOS(ui_task_runner, socket_thread));
67 BluetoothSocketChromeOS::AcceptRequest::AcceptRequest() {}
69 BluetoothSocketChromeOS::AcceptRequest::~AcceptRequest() {}
71 BluetoothSocketChromeOS::ConnectionRequest::ConnectionRequest()
72 : accepting(false),
73 cancelled(false) {}
75 BluetoothSocketChromeOS::ConnectionRequest::~ConnectionRequest() {}
77 BluetoothSocketChromeOS::BluetoothSocketChromeOS(
78 scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
79 scoped_refptr<BluetoothSocketThread> socket_thread)
80 : BluetoothSocketNet(ui_task_runner, socket_thread), profile_(nullptr) {
83 BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
84 DCHECK(!profile_);
86 if (adapter_.get()) {
87 adapter_->RemoveObserver(this);
88 adapter_ = NULL;
92 void BluetoothSocketChromeOS::Connect(
93 const BluetoothDeviceChromeOS* 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_);
101 if (!uuid.IsValid()) {
102 error_callback.Run(kInvalidUUID);
103 return;
106 device_address_ = device->GetAddress();
107 device_path_ = device->object_path();
108 uuid_ = uuid;
109 options_.reset(new BluetoothProfileManagerClient::Options());
110 if (security_level == SECURITY_LEVEL_LOW)
111 options_->require_authentication.reset(new bool(false));
113 RegisterProfile(device->adapter(), success_callback, error_callback);
116 void BluetoothSocketChromeOS::Listen(
117 scoped_refptr<BluetoothAdapter> adapter,
118 SocketType socket_type,
119 const BluetoothUUID& uuid,
120 const BluetoothAdapter::ServiceOptions& service_options,
121 const base::Closure& success_callback,
122 const ErrorCompletionCallback& error_callback) {
123 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
124 DCHECK(!profile_);
126 if (!uuid.IsValid()) {
127 error_callback.Run(kInvalidUUID);
128 return;
131 adapter->AddObserver(this);
133 uuid_ = uuid;
134 options_.reset(new BluetoothProfileManagerClient::Options());
135 if (service_options.name)
136 options_->name.reset(new std::string(*service_options.name));
138 switch (socket_type) {
139 case kRfcomm:
140 options_->channel.reset(
141 new uint16(service_options.channel ? *service_options.channel : 0));
142 break;
143 case kL2cap:
144 options_->psm.reset(
145 new uint16(service_options.psm ? *service_options.psm : 0));
146 break;
147 default:
148 NOTREACHED();
151 RegisterProfile(static_cast<BluetoothAdapterChromeOS*>(adapter.get()),
152 success_callback, error_callback);
155 void BluetoothSocketChromeOS::Close() {
156 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
158 if (profile_)
159 UnregisterProfile();
161 // In the case below, where an asynchronous task gets posted on the socket
162 // thread in BluetoothSocketNet::Close, a reference will be held to this
163 // socket by the callback. This may cause the BluetoothAdapter to outlive
164 // DBusThreadManager during shutdown if that callback executes too late.
165 if (adapter_.get()) {
166 adapter_->RemoveObserver(this);
167 adapter_ = NULL;
170 if (!device_path_.value().empty()) {
171 BluetoothSocketNet::Close();
172 } else {
173 DoCloseListening();
177 void BluetoothSocketChromeOS::Disconnect(const base::Closure& callback) {
178 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
180 if (profile_)
181 UnregisterProfile();
183 if (!device_path_.value().empty()) {
184 BluetoothSocketNet::Disconnect(callback);
185 } else {
186 DoCloseListening();
187 callback.Run();
191 void BluetoothSocketChromeOS::Accept(
192 const AcceptCompletionCallback& success_callback,
193 const ErrorCompletionCallback& error_callback) {
194 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
196 if (!device_path_.value().empty()) {
197 error_callback.Run(kSocketNotListening);
198 return;
201 // Only one pending accept at a time
202 if (accept_request_.get()) {
203 error_callback.Run(net::ErrorToString(net::ERR_IO_PENDING));
204 return;
207 accept_request_.reset(new AcceptRequest);
208 accept_request_->success_callback = success_callback;
209 accept_request_->error_callback = error_callback;
211 if (connection_request_queue_.size() >= 1) {
212 AcceptConnectionRequest();
216 void BluetoothSocketChromeOS::RegisterProfile(
217 BluetoothAdapterChromeOS* adapter,
218 const base::Closure& success_callback,
219 const ErrorCompletionCallback& error_callback) {
220 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
221 DCHECK(!profile_);
222 DCHECK(adapter);
224 adapter_ = adapter;
226 // If the adapter is not present, this is a listening socket and the
227 // adapter isn't running yet. Report success and carry on;
228 // the profile will be registered when the daemon becomes available.
229 if (!adapter_->IsPresent()) {
230 VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
231 << ": Delaying profile registration.";
232 base::MessageLoop::current()->PostTask(FROM_HERE, success_callback);
233 return;
236 VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
237 << ": Acquiring profile.";
239 adapter->UseProfile(
240 uuid_, device_path_, *options_, this,
241 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile, this,
242 success_callback, error_callback),
243 base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError, this,
244 error_callback));
247 void BluetoothSocketChromeOS::OnRegisterProfile(
248 const base::Closure& success_callback,
249 const ErrorCompletionCallback& error_callback,
250 BluetoothAdapterProfileChromeOS* profile) {
251 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
252 DCHECK(!profile_);
254 profile_ = profile;
256 if (device_path_.value().empty()) {
257 VLOG(1) << uuid_.canonical_value() << ": Profile registered.";
258 success_callback.Run();
259 return;
262 VLOG(1) << uuid_.canonical_value() << ": Got profile, connecting to "
263 << device_path_.value();
265 DBusThreadManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
266 device_path_, uuid_.canonical_value(),
267 base::Bind(&BluetoothSocketChromeOS::OnConnectProfile, this,
268 success_callback),
269 base::Bind(&BluetoothSocketChromeOS::OnConnectProfileError, this,
270 error_callback));
273 void BluetoothSocketChromeOS::OnRegisterProfileError(
274 const ErrorCompletionCallback& error_callback,
275 const std::string& error_message) {
276 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
278 LOG(WARNING) << uuid_.canonical_value()
279 << ": Failed to register profile: " << error_message;
280 error_callback.Run(error_message);
283 void BluetoothSocketChromeOS::OnConnectProfile(
284 const base::Closure& success_callback) {
285 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
286 DCHECK(profile_);
288 VLOG(1) << profile_->object_path().value() << ": Profile connected.";
289 UnregisterProfile();
290 success_callback.Run();
293 void BluetoothSocketChromeOS::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_);
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);
307 void BluetoothSocketChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter,
308 bool present) {
309 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
311 if (!present) {
312 // Adapter removed, the profile is now invalid.
313 UnregisterProfile();
314 return;
317 DCHECK(!profile_);
319 VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
320 << ": Acquiring profile.";
322 static_cast<BluetoothAdapterChromeOS*>(adapter)->UseProfile(
323 uuid_, device_path_, *options_, this,
324 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile, this),
325 base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError,
326 this));
329 void BluetoothSocketChromeOS::OnInternalRegisterProfile(
330 BluetoothAdapterProfileChromeOS* profile) {
331 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
332 DCHECK(!profile_);
334 profile_ = profile;
336 VLOG(1) << uuid_.canonical_value() << ": Profile re-registered";
339 void BluetoothSocketChromeOS::OnInternalRegisterProfileError(
340 const std::string& error_message) {
341 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
343 LOG(WARNING) << "Failed to re-register profile: " << error_message;
346 void BluetoothSocketChromeOS::Released() {
347 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
348 DCHECK(profile_);
350 VLOG(1) << profile_->object_path().value() << ": Release";
353 void BluetoothSocketChromeOS::NewConnection(
354 const dbus::ObjectPath& device_path,
355 scoped_ptr<dbus::FileDescriptor> fd,
356 const BluetoothProfileServiceProvider::Delegate::Options& options,
357 const ConfirmationCallback& callback) {
358 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
360 VLOG(1) << uuid_.canonical_value()
361 << ": New connection from device: " << device_path.value();
363 if (!device_path_.value().empty()) {
364 DCHECK(device_path_ == device_path);
366 socket_thread()->task_runner()->PostTask(
367 FROM_HERE,
368 base::Bind(
369 &BluetoothSocketChromeOS::DoNewConnection,
370 this,
371 device_path_,
372 base::Passed(&fd),
373 options,
374 callback));
375 } else {
376 linked_ptr<ConnectionRequest> request(new ConnectionRequest());
377 request->device_path = device_path;
378 request->fd = fd.Pass();
379 request->options = options;
380 request->callback = callback;
382 connection_request_queue_.push(request);
383 VLOG(1) << uuid_.canonical_value() << ": Connection is now pending.";
384 if (accept_request_) {
385 AcceptConnectionRequest();
390 void BluetoothSocketChromeOS::RequestDisconnection(
391 const dbus::ObjectPath& device_path,
392 const ConfirmationCallback& callback) {
393 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
394 DCHECK(profile_);
396 VLOG(1) << profile_->object_path().value() << ": Request disconnection";
397 callback.Run(SUCCESS);
400 void BluetoothSocketChromeOS::Cancel() {
401 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
402 DCHECK(profile_);
404 VLOG(1) << profile_->object_path().value() << ": Cancel";
406 if (!connection_request_queue_.size())
407 return;
409 // If the front request is being accepted mark it as cancelled, otherwise
410 // just pop it from the queue.
411 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
412 if (!request->accepting) {
413 request->cancelled = true;
414 } else {
415 connection_request_queue_.pop();
419 void BluetoothSocketChromeOS::AcceptConnectionRequest() {
420 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
421 DCHECK(accept_request_.get());
422 DCHECK(connection_request_queue_.size() >= 1);
423 DCHECK(profile_);
425 VLOG(1) << profile_->object_path().value()
426 << ": Accepting pending connection.";
428 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
429 request->accepting = true;
431 BluetoothDeviceChromeOS* device =
432 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())->
433 GetDeviceWithPath(request->device_path);
434 DCHECK(device);
436 scoped_refptr<BluetoothSocketChromeOS> client_socket =
437 BluetoothSocketChromeOS::CreateBluetoothSocket(
438 ui_task_runner(), socket_thread());
440 client_socket->device_address_ = device->GetAddress();
441 client_socket->device_path_ = request->device_path;
442 client_socket->uuid_ = uuid_;
444 socket_thread()->task_runner()->PostTask(
445 FROM_HERE,
446 base::Bind(
447 &BluetoothSocketChromeOS::DoNewConnection,
448 client_socket,
449 request->device_path,
450 base::Passed(&request->fd),
451 request->options,
452 base::Bind(&BluetoothSocketChromeOS::OnNewConnection,
453 this,
454 client_socket,
455 request->callback)));
458 void BluetoothSocketChromeOS::DoNewConnection(
459 const dbus::ObjectPath& device_path,
460 scoped_ptr<dbus::FileDescriptor> fd,
461 const BluetoothProfileServiceProvider::Delegate::Options& options,
462 const ConfirmationCallback& callback) {
463 DCHECK(socket_thread()->task_runner()->RunsTasksOnCurrentThread());
464 base::ThreadRestrictions::AssertIOAllowed();
465 fd->CheckValidity();
467 VLOG(1) << uuid_.canonical_value() << ": Validity check complete.";
468 if (!fd->is_valid()) {
469 LOG(WARNING) << uuid_.canonical_value() << " :" << fd->value()
470 << ": Invalid file descriptor received from Bluetooth Daemon.";
471 ui_task_runner()->PostTask(FROM_HERE,
472 base::Bind(callback, REJECTED));;
473 return;
476 if (tcp_socket()) {
477 LOG(WARNING) << uuid_.canonical_value() << ": Already connected";
478 ui_task_runner()->PostTask(FROM_HERE,
479 base::Bind(callback, REJECTED));;
480 return;
483 ResetTCPSocket();
485 // Note: We don't have a meaningful |IPEndPoint|, but that is ok since the
486 // TCPSocket implementation does not actually require one.
487 int net_result = tcp_socket()->AdoptConnectedSocket(fd->value(),
488 net::IPEndPoint());
489 if (net_result != net::OK) {
490 LOG(WARNING) << uuid_.canonical_value() << ": Error adopting socket: "
491 << std::string(net::ErrorToString(net_result));
492 ui_task_runner()->PostTask(FROM_HERE,
493 base::Bind(callback, REJECTED));;
494 return;
497 VLOG(2) << uuid_.canonical_value()
498 << ": Taking descriptor, confirming success.";
499 fd->TakeValue();
500 ui_task_runner()->PostTask(FROM_HERE,
501 base::Bind(callback, SUCCESS));;
504 void BluetoothSocketChromeOS::OnNewConnection(
505 scoped_refptr<BluetoothSocket> socket,
506 const ConfirmationCallback& callback,
507 Status status) {
508 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
509 DCHECK(accept_request_.get());
510 DCHECK(connection_request_queue_.size() >= 1);
512 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
513 if (status == SUCCESS && !request->cancelled) {
514 BluetoothDeviceChromeOS* device =
515 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())->
516 GetDeviceWithPath(request->device_path);
517 DCHECK(device);
519 accept_request_->success_callback.Run(device, socket);
520 } else {
521 accept_request_->error_callback.Run(kAcceptFailed);
524 accept_request_.reset(NULL);
525 connection_request_queue_.pop();
527 callback.Run(status);
530 void BluetoothSocketChromeOS::DoCloseListening() {
531 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
533 if (accept_request_) {
534 accept_request_->error_callback.Run(
535 net::ErrorToString(net::ERR_CONNECTION_CLOSED));
536 accept_request_.reset(NULL);
539 while (connection_request_queue_.size() > 0) {
540 linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
541 request->callback.Run(REJECTED);
542 connection_request_queue_.pop();
546 void BluetoothSocketChromeOS::UnregisterProfile() {
547 DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
548 DCHECK(profile_);
550 VLOG(1) << profile_->object_path().value() << ": Release profile";
552 profile_->RemoveDelegate(
553 device_path_,
554 base::Bind(&BluetoothSocketChromeOS::ReleaseProfile, this, profile_));
556 profile_ = nullptr;
559 void BluetoothSocketChromeOS::ReleaseProfile(
560 BluetoothAdapterProfileChromeOS* profile) {
561 if (adapter_)
562 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())
563 ->ReleaseProfile(uuid_);
564 else
565 delete profile;
568 } // namespace chromeos