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_profile_chromeos.h"
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"
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 #include "third_party/cros_system_api/dbus/service_constants.h"
35 using device::BluetoothAdapter
;
36 using device::BluetoothAdapterFactory
;
37 using device::BluetoothDevice
;
38 using device::BluetoothProfile
;
39 using device::BluetoothSocket
;
43 // Check the validity of a file descriptor received from D-Bus. Must be run
44 // on a thread where i/o is permitted.
45 scoped_ptr
<dbus::FileDescriptor
> CheckValidity(
46 scoped_ptr
<dbus::FileDescriptor
> fd
) {
47 base::ThreadRestrictions::AssertIOAllowed();
57 BluetoothProfileChromeOS::BluetoothProfileChromeOS()
58 : weak_ptr_factory_(this) {
61 BluetoothProfileChromeOS::~BluetoothProfileChromeOS() {
62 DCHECK(object_path_
.value().empty());
63 DCHECK(profile_
.get() == NULL
);
66 adapter_
->RemoveObserver(this);
71 void BluetoothProfileChromeOS::Init(
72 const device::BluetoothUUID
& uuid
,
73 const device::BluetoothProfile::Options
& options
,
74 const ProfileCallback
& callback
) {
75 DCHECK(object_path_
.value().empty());
76 DCHECK(profile_
.get() == NULL
);
78 if (!uuid
.IsValid()) {
85 options_
.name
= options
.name
;
86 options_
.service
= uuid
.canonical_value();
87 options_
.channel
= options
.channel
;
88 options_
.psm
= options
.psm
;
89 options_
.require_authentication
= options
.require_authentication
;
90 options_
.require_authorization
= options
.require_authorization
;
91 options_
.auto_connect
= options
.auto_connect
;
92 options_
.version
= options
.version
;
93 options_
.features
= options
.features
;
95 // The object path is relatively meaningless, but has to be unique, so we
96 // use the UUID of the profile.
97 std::string uuid_path
;
98 base::ReplaceChars(uuid
.canonical_value(), ":-", "_", &uuid_path
);
100 object_path_
= dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
103 dbus::Bus
* system_bus
= DBusThreadManager::Get()->GetSystemBus();
104 profile_
.reset(BluetoothProfileServiceProvider::Create(
105 system_bus
, object_path_
, this));
106 DCHECK(profile_
.get());
108 // Now the profile object is registered we need an adapter to register it
110 BluetoothAdapterFactory::GetAdapter(
111 base::Bind(&BluetoothProfileChromeOS::OnGetAdapter
,
112 weak_ptr_factory_
.GetWeakPtr(),
116 void BluetoothProfileChromeOS::Unregister() {
117 DCHECK(!object_path_
.value().empty());
118 DCHECK(profile_
.get());
122 VLOG(1) << object_path_
.value() << ": Unregister profile";
123 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
126 base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfile
,
127 weak_ptr_factory_
.GetWeakPtr()),
128 base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfileError
,
129 weak_ptr_factory_
.GetWeakPtr()));
132 void BluetoothProfileChromeOS::SetConnectionCallback(
133 const ConnectionCallback
& callback
) {
134 connection_callback_
= callback
;
137 void BluetoothProfileChromeOS::AdapterPresentChanged(BluetoothAdapter
* adapter
,
142 VLOG(1) << object_path_
.value() << ": Register profile";
143 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
146 uuid_
.canonical_value(),
148 base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfile
,
149 weak_ptr_factory_
.GetWeakPtr()),
150 base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfileError
,
151 weak_ptr_factory_
.GetWeakPtr()));
154 void BluetoothProfileChromeOS::OnGetAdapter(
155 const ProfileCallback
& callback
,
156 scoped_refptr
<device::BluetoothAdapter
> adapter
) {
157 DCHECK(!adapter_
.get());
159 adapter_
->AddObserver(this);
161 VLOG(1) << object_path_
.value() << ": Register profile";
162 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
165 uuid_
.canonical_value(),
167 base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile
,
168 weak_ptr_factory_
.GetWeakPtr(),
170 base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError
,
171 weak_ptr_factory_
.GetWeakPtr(),
175 void BluetoothProfileChromeOS::Release() {
176 VLOG(1) << object_path_
.value() << ": Release";
179 void BluetoothProfileChromeOS::NewConnection(
180 const dbus::ObjectPath
& device_path
,
181 scoped_ptr
<dbus::FileDescriptor
> fd
,
182 const BluetoothProfileServiceProvider::Delegate::Options
& options
,
183 const ConfirmationCallback
& callback
) {
184 VLOG(1) << object_path_
.value() << ": New connection from device: "
185 << device_path
.value();
186 if (connection_callback_
.is_null()) {
187 callback
.Run(REJECTED
);
191 // Punt descriptor validity check to a worker thread where i/o is permitted;
192 // on return we'll call the connection callback.
194 // base::Passed is used to take ownership of the file descriptor during the
195 // CheckValidity() call and pass that ownership to callback.
196 base::PostTaskAndReplyWithResult(
197 base::WorkerPool::GetTaskRunner(false).get(),
199 base::Bind(&CheckValidity
, base::Passed(&fd
)),
200 base::Bind(&BluetoothProfileChromeOS::OnCheckValidity
,
201 weak_ptr_factory_
.GetWeakPtr(),
207 void BluetoothProfileChromeOS::RequestDisconnection(
208 const dbus::ObjectPath
& device_path
,
209 const ConfirmationCallback
& callback
) {
210 VLOG(1) << object_path_
.value() << ": Request disconnection";
211 callback
.Run(SUCCESS
);
214 void BluetoothProfileChromeOS::Cancel() {
215 VLOG(1) << object_path_
.value() << ": Cancel";
218 void BluetoothProfileChromeOS::OnInternalRegisterProfile() {
219 VLOG(1) << object_path_
.value() << ": Profile registered";
222 void BluetoothProfileChromeOS::OnInternalRegisterProfileError(
223 const std::string
& error_name
,
224 const std::string
& error_message
) {
225 // It's okay if the profile already exists, it means we registered it on
227 if (error_name
== bluetooth_profile_manager::kErrorAlreadyExists
)
230 LOG(WARNING
) << object_path_
.value() << ": Failed to register profile: "
231 << error_name
<< ": " << error_message
;
234 void BluetoothProfileChromeOS::OnRegisterProfile(
235 const ProfileCallback
& callback
) {
236 VLOG(1) << object_path_
.value() << ": Profile registered";
240 void BluetoothProfileChromeOS::OnRegisterProfileError(
241 const ProfileCallback
& callback
,
242 const std::string
& error_name
,
243 const std::string
& error_message
) {
244 // It's okay if the profile already exists, it means we registered it when
245 // we first saw the adapter.
246 if (error_name
== bluetooth_profile_manager::kErrorAlreadyExists
)
249 LOG(WARNING
) << object_path_
.value() << ": Failed to register profile: "
250 << error_name
<< ": " << error_message
;
254 void BluetoothProfileChromeOS::OnUnregisterProfile() {
255 VLOG(1) << object_path_
.value() << ": Profile unregistered";
256 object_path_
= dbus::ObjectPath("");
260 void BluetoothProfileChromeOS::OnUnregisterProfileError(
261 const std::string
& error_name
,
262 const std::string
& error_message
) {
263 // It's okay if the profile didn't exist, it means we never saw an adapter.
264 if (error_name
== bluetooth_profile_manager::kErrorDoesNotExist
)
267 LOG(WARNING
) << object_path_
.value() << ": Failed to unregister profile: "
268 << error_name
<< ": " << error_message
;
269 object_path_
= dbus::ObjectPath("");
273 void BluetoothProfileChromeOS::OnCheckValidity(
274 const dbus::ObjectPath
& device_path
,
275 const BluetoothProfileServiceProvider::Delegate::Options
& options
,
276 const ConfirmationCallback
& callback
,
277 scoped_ptr
<dbus::FileDescriptor
> fd
) {
278 VLOG(1) << object_path_
.value() << ": Validity check complete";
279 if (!fd
->is_valid()) {
280 callback
.Run(REJECTED
);
284 callback
.Run(SUCCESS
);
286 BluetoothDeviceChromeOS
* device
=
287 static_cast<BluetoothAdapterChromeOS
*>(adapter_
.get())->
288 GetDeviceWithPath(device_path
);
291 scoped_refptr
<BluetoothSocket
> socket((
292 BluetoothSocketChromeOS::Create(fd
.get())));
293 connection_callback_
.Run(device
, socket
);
296 } // namespace chromeos