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 base::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