// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "device/bluetooth/bluetooth_profile_chromeos.h" #include #include "base/basictypes.h" #include "base/bind.h" #include "base/callback.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/strings/string_util.h" #include "base/task_runner_util.h" #include "base/threading/thread_restrictions.h" #include "base/threading/worker_pool.h" #include "chromeos/dbus/bluetooth_profile_manager_client.h" #include "chromeos/dbus/bluetooth_profile_service_provider.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "dbus/bus.h" #include "dbus/file_descriptor.h" #include "dbus/object_path.h" #include "device/bluetooth/bluetooth_adapter_chromeos.h" #include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_device_chromeos.h" #include "device/bluetooth/bluetooth_profile.h" #include "device/bluetooth/bluetooth_socket.h" #include "device/bluetooth/bluetooth_socket_chromeos.h" using device::BluetoothAdapter; using device::BluetoothAdapterFactory; using device::BluetoothDevice; using device::BluetoothProfile; using device::BluetoothSocket; namespace { // Check the validity of a file descriptor received from D-Bus. Must be run // on a thread where i/o is permitted. scoped_ptr CheckValidity( scoped_ptr fd) { base::ThreadRestrictions::AssertIOAllowed(); fd->CheckValidity(); return fd.Pass(); } } // namespace namespace chromeos { BluetoothProfileChromeOS::BluetoothProfileChromeOS() : weak_ptr_factory_(this) { } BluetoothProfileChromeOS::~BluetoothProfileChromeOS() { DCHECK(object_path_.value().empty()); DCHECK(profile_.get() == NULL); } void BluetoothProfileChromeOS::Init( const std::string& uuid, const device::BluetoothProfile::Options& options, const ProfileCallback& callback) { DCHECK(object_path_.value().empty()); DCHECK(profile_.get() == NULL); if (!BluetoothDevice::IsUUIDValid(uuid)) { callback.Run(NULL); return; } uuid_ = uuid; BluetoothProfileManagerClient::Options bluetooth_options; bluetooth_options.name = options.name; bluetooth_options.service = uuid; bluetooth_options.channel = options.channel; bluetooth_options.psm = options.psm; bluetooth_options.require_authentication = options.require_authentication; bluetooth_options.require_authorization = options.require_authorization; bluetooth_options.auto_connect = options.auto_connect; bluetooth_options.version = options.version; bluetooth_options.features = options.features; // The object path is relatively meaningless, but has to be unique, so we // use the UUID of the profile. std::string uuid_path; ReplaceChars(uuid, ":-", "_", &uuid_path); object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" + uuid_path); dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); profile_.reset(BluetoothProfileServiceProvider::Create( system_bus, object_path_, this)); DCHECK(profile_.get()); VLOG(1) << object_path_.value() << ": Register profile"; DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> RegisterProfile( object_path_, uuid, bluetooth_options, base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile, weak_ptr_factory_.GetWeakPtr(), callback), base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError, weak_ptr_factory_.GetWeakPtr(), callback)); } void BluetoothProfileChromeOS::Unregister() { DCHECK(!object_path_.value().empty()); DCHECK(profile_.get()); profile_.reset(); VLOG(1) << object_path_.value() << ": Unregister profile"; DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> UnregisterProfile( object_path_, base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfile, weak_ptr_factory_.GetWeakPtr()), base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfileError, weak_ptr_factory_.GetWeakPtr())); } void BluetoothProfileChromeOS::SetConnectionCallback( const ConnectionCallback& callback) { connection_callback_ = callback; } void BluetoothProfileChromeOS::Release() { VLOG(1) << object_path_.value() << ": Release"; } void BluetoothProfileChromeOS::NewConnection( const dbus::ObjectPath& device_path, scoped_ptr fd, const BluetoothProfileServiceProvider::Delegate::Options& options, const ConfirmationCallback& callback) { VLOG(1) << object_path_.value() << ": New connection from device: " << device_path.value();; if (connection_callback_.is_null()) { callback.Run(REJECTED); return; } // Punt descriptor validity check to a worker thread where i/o is permitted; // on return we'll fetch the adapter and then call the connection callback. // // base::Passed is used to take ownership of the file descriptor during the // CheckValidity() call and pass that ownership to the GetAdapter() call. base::PostTaskAndReplyWithResult( base::WorkerPool::GetTaskRunner(false).get(), FROM_HERE, base::Bind(&CheckValidity, base::Passed(&fd)), base::Bind(&BluetoothProfileChromeOS::GetAdapter, weak_ptr_factory_.GetWeakPtr(), device_path, options, callback)); } void BluetoothProfileChromeOS::RequestDisconnection( const dbus::ObjectPath& device_path, const ConfirmationCallback& callback) { VLOG(1) << object_path_.value() << ": Request disconnection"; callback.Run(SUCCESS); } void BluetoothProfileChromeOS::Cancel() { VLOG(1) << object_path_.value() << ": Cancel"; } void BluetoothProfileChromeOS::OnRegisterProfile( const ProfileCallback& callback) { VLOG(1) << object_path_.value() << ": Profile registered"; callback.Run(this); } void BluetoothProfileChromeOS::OnRegisterProfileError( const ProfileCallback& callback, const std::string& error_name, const std::string& error_message) { LOG(WARNING) << object_path_.value() << ": Failed to register profile: " << error_name << ": " << error_message; callback.Run(NULL); Unregister(); } void BluetoothProfileChromeOS::OnUnregisterProfile() { VLOG(1) << object_path_.value() << ": Profile unregistered"; object_path_ = dbus::ObjectPath(""); delete this; } void BluetoothProfileChromeOS::OnUnregisterProfileError( const std::string& error_name, const std::string& error_message) { LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: " << error_name << ": " << error_message; object_path_ = dbus::ObjectPath(""); delete this; } void BluetoothProfileChromeOS::GetAdapter( const dbus::ObjectPath& device_path, const BluetoothProfileServiceProvider::Delegate::Options& options, const ConfirmationCallback& callback, scoped_ptr fd) { VLOG(1) << object_path_.value() << ": Validity check complete"; if (!fd->is_valid()) { callback.Run(REJECTED); return; } BluetoothAdapterFactory::GetAdapter( base::Bind(&BluetoothProfileChromeOS::OnGetAdapter, weak_ptr_factory_.GetWeakPtr(), device_path, options, callback, base::Passed(&fd))); } void BluetoothProfileChromeOS::OnGetAdapter( const dbus::ObjectPath& device_path, const BluetoothProfileServiceProvider::Delegate::Options& options, const ConfirmationCallback& callback, scoped_ptr fd, scoped_refptr adapter) { VLOG(1) << object_path_.value() << ": Obtained adapter reference"; callback.Run(SUCCESS); BluetoothDeviceChromeOS* device = static_cast(adapter.get())-> GetDeviceWithPath(device_path); DCHECK(device); scoped_refptr socket(( BluetoothSocketChromeOS::Create(fd.get()))); connection_callback_.Run(device, socket); } } // namespace chromeos