Home | History | Annotate | Download | only in bluetooth
      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_profile_chromeos.h"
      6 
      7 #include <string>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/callback.h"
     12 #include "base/logging.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/memory/weak_ptr.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/task_runner_util.h"
     18 #include "base/threading/thread_restrictions.h"
     19 #include "base/threading/worker_pool.h"
     20 #include "chromeos/dbus/bluetooth_profile_manager_client.h"
     21 #include "chromeos/dbus/bluetooth_profile_service_provider.h"
     22 #include "chromeos/dbus/dbus_thread_manager.h"
     23 #include "dbus/bus.h"
     24 #include "dbus/file_descriptor.h"
     25 #include "dbus/object_path.h"
     26 #include "device/bluetooth/bluetooth_adapter_chromeos.h"
     27 #include "device/bluetooth/bluetooth_adapter_factory.h"
     28 #include "device/bluetooth/bluetooth_device.h"
     29 #include "device/bluetooth/bluetooth_device_chromeos.h"
     30 #include "device/bluetooth/bluetooth_profile.h"
     31 #include "device/bluetooth/bluetooth_socket.h"
     32 #include "device/bluetooth/bluetooth_socket_chromeos.h"
     33 
     34 using device::BluetoothAdapter;
     35 using device::BluetoothAdapterFactory;
     36 using device::BluetoothDevice;
     37 using device::BluetoothProfile;
     38 using device::BluetoothSocket;
     39 
     40 namespace {
     41 
     42 // Check the validity of a file descriptor received from D-Bus. Must be run
     43 // on a thread where i/o is permitted.
     44 scoped_ptr<dbus::FileDescriptor> CheckValidity(
     45     scoped_ptr<dbus::FileDescriptor> fd) {
     46   base::ThreadRestrictions::AssertIOAllowed();
     47   fd->CheckValidity();
     48   return fd.Pass();
     49 }
     50 
     51 }  // namespace
     52 
     53 
     54 namespace chromeos {
     55 
     56 BluetoothProfileChromeOS::BluetoothProfileChromeOS()
     57     : weak_ptr_factory_(this) {
     58 }
     59 
     60 BluetoothProfileChromeOS::~BluetoothProfileChromeOS() {
     61   DCHECK(object_path_.value().empty());
     62   DCHECK(profile_.get() == NULL);
     63 }
     64 
     65 void BluetoothProfileChromeOS::Init(
     66     const std::string& uuid,
     67     const device::BluetoothProfile::Options& options,
     68     const ProfileCallback& callback) {
     69   DCHECK(object_path_.value().empty());
     70   DCHECK(profile_.get() == NULL);
     71 
     72   if (!BluetoothDevice::IsUUIDValid(uuid)) {
     73     callback.Run(NULL);
     74     return;
     75   }
     76 
     77   uuid_ = uuid;
     78 
     79   BluetoothProfileManagerClient::Options bluetooth_options;
     80   bluetooth_options.name = options.name;
     81   bluetooth_options.service = uuid;
     82   bluetooth_options.channel = options.channel;
     83   bluetooth_options.psm = options.psm;
     84   bluetooth_options.require_authentication = options.require_authentication;
     85   bluetooth_options.require_authorization = options.require_authorization;
     86   bluetooth_options.auto_connect = options.auto_connect;
     87   bluetooth_options.version = options.version;
     88   bluetooth_options.features = options.features;
     89 
     90   // The object path is relatively meaningless, but has to be unique, so we
     91   // use the UUID of the profile.
     92   std::string uuid_path;
     93   ReplaceChars(uuid, ":-", "_", &uuid_path);
     94 
     95   object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
     96                                   uuid_path);
     97 
     98   dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
     99   profile_.reset(BluetoothProfileServiceProvider::Create(
    100       system_bus, object_path_, this));
    101   DCHECK(profile_.get());
    102 
    103   VLOG(1) << object_path_.value() << ": Register profile";
    104   DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
    105       RegisterProfile(
    106           object_path_,
    107           uuid,
    108           bluetooth_options,
    109           base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile,
    110                      weak_ptr_factory_.GetWeakPtr(),
    111                      callback),
    112           base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError,
    113                      weak_ptr_factory_.GetWeakPtr(),
    114                      callback));
    115 }
    116 
    117 void BluetoothProfileChromeOS::Unregister() {
    118   DCHECK(!object_path_.value().empty());
    119   DCHECK(profile_.get());
    120 
    121   profile_.reset();
    122 
    123   VLOG(1) << object_path_.value() << ": Unregister profile";
    124   DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
    125       UnregisterProfile(
    126           object_path_,
    127           base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfile,
    128                      weak_ptr_factory_.GetWeakPtr()),
    129           base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfileError,
    130                      weak_ptr_factory_.GetWeakPtr()));
    131 }
    132 
    133 void BluetoothProfileChromeOS::SetConnectionCallback(
    134     const ConnectionCallback& callback) {
    135   connection_callback_ = callback;
    136 }
    137 
    138 void BluetoothProfileChromeOS::Release() {
    139   VLOG(1) << object_path_.value() << ": Release";
    140 }
    141 
    142 void BluetoothProfileChromeOS::NewConnection(
    143     const dbus::ObjectPath& device_path,
    144     scoped_ptr<dbus::FileDescriptor> fd,
    145     const BluetoothProfileServiceProvider::Delegate::Options& options,
    146     const ConfirmationCallback& callback) {
    147   VLOG(1) << object_path_.value() << ": New connection from device: "
    148           << device_path.value();;
    149   if (connection_callback_.is_null()) {
    150     callback.Run(REJECTED);
    151     return;
    152   }
    153 
    154   // Punt descriptor validity check to a worker thread where i/o is permitted;
    155   // on return we'll fetch the adapter and then call the connection callback.
    156   //
    157   // base::Passed is used to take ownership of the file descriptor during the
    158   // CheckValidity() call and pass that ownership to the GetAdapter() call.
    159   base::PostTaskAndReplyWithResult(
    160       base::WorkerPool::GetTaskRunner(false).get(),
    161       FROM_HERE,
    162       base::Bind(&CheckValidity, base::Passed(&fd)),
    163       base::Bind(&BluetoothProfileChromeOS::GetAdapter,
    164                  weak_ptr_factory_.GetWeakPtr(),
    165                  device_path,
    166                  options,
    167                  callback));
    168 }
    169 
    170 void BluetoothProfileChromeOS::RequestDisconnection(
    171     const dbus::ObjectPath& device_path,
    172     const ConfirmationCallback& callback) {
    173   VLOG(1) << object_path_.value() << ": Request disconnection";
    174   callback.Run(SUCCESS);
    175 }
    176 
    177 void BluetoothProfileChromeOS::Cancel() {
    178   VLOG(1) << object_path_.value() << ": Cancel";
    179 }
    180 
    181 void BluetoothProfileChromeOS::OnRegisterProfile(
    182     const ProfileCallback& callback) {
    183   VLOG(1) << object_path_.value() << ": Profile registered";
    184   callback.Run(this);
    185 }
    186 
    187 void BluetoothProfileChromeOS::OnRegisterProfileError(
    188     const ProfileCallback& callback,
    189     const std::string& error_name,
    190     const std::string& error_message) {
    191   LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
    192                << error_name << ": " << error_message;
    193   callback.Run(NULL);
    194 
    195   Unregister();
    196 }
    197 
    198 void BluetoothProfileChromeOS::OnUnregisterProfile() {
    199   VLOG(1) << object_path_.value() << ": Profile unregistered";
    200   object_path_ = dbus::ObjectPath("");
    201   delete this;
    202 }
    203 
    204 void BluetoothProfileChromeOS::OnUnregisterProfileError(
    205     const std::string& error_name,
    206     const std::string& error_message) {
    207   LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: "
    208                << error_name << ": " << error_message;
    209   object_path_ = dbus::ObjectPath("");
    210   delete this;
    211 }
    212 
    213 void BluetoothProfileChromeOS::GetAdapter(
    214       const dbus::ObjectPath& device_path,
    215       const BluetoothProfileServiceProvider::Delegate::Options& options,
    216       const ConfirmationCallback& callback,
    217       scoped_ptr<dbus::FileDescriptor> fd) {
    218   VLOG(1) << object_path_.value() << ": Validity check complete";
    219   if (!fd->is_valid()) {
    220     callback.Run(REJECTED);
    221     return;
    222   }
    223 
    224   BluetoothAdapterFactory::GetAdapter(
    225       base::Bind(&BluetoothProfileChromeOS::OnGetAdapter,
    226                  weak_ptr_factory_.GetWeakPtr(),
    227                  device_path,
    228                  options,
    229                  callback,
    230                  base::Passed(&fd)));
    231 }
    232 
    233 void BluetoothProfileChromeOS::OnGetAdapter(
    234     const dbus::ObjectPath& device_path,
    235     const BluetoothProfileServiceProvider::Delegate::Options&
    236         options,
    237     const ConfirmationCallback& callback,
    238     scoped_ptr<dbus::FileDescriptor> fd,
    239     scoped_refptr<BluetoothAdapter> adapter) {
    240   VLOG(1) << object_path_.value() << ": Obtained adapter reference";
    241   callback.Run(SUCCESS);
    242 
    243   BluetoothDeviceChromeOS* device =
    244       static_cast<BluetoothAdapterChromeOS*>(adapter.get())->
    245           GetDeviceWithPath(device_path);
    246   DCHECK(device);
    247 
    248   scoped_refptr<BluetoothSocket> socket((
    249       BluetoothSocketChromeOS::Create(fd.get())));
    250   connection_callback_.Run(device, socket);
    251 }
    252 
    253 }  // namespace chromeos
    254