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.
CheckValidity(scoped_ptr<dbus::FileDescriptor> fd)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
BluetoothProfileChromeOS()56 BluetoothProfileChromeOS::BluetoothProfileChromeOS()
57 : weak_ptr_factory_(this) {
58 }
59
~BluetoothProfileChromeOS()60 BluetoothProfileChromeOS::~BluetoothProfileChromeOS() {
61 DCHECK(object_path_.value().empty());
62 DCHECK(profile_.get() == NULL);
63 }
64
Init(const std::string & uuid,const device::BluetoothProfile::Options & options,const ProfileCallback & callback)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
Unregister()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
SetConnectionCallback(const ConnectionCallback & callback)133 void BluetoothProfileChromeOS::SetConnectionCallback(
134 const ConnectionCallback& callback) {
135 connection_callback_ = callback;
136 }
137
Release()138 void BluetoothProfileChromeOS::Release() {
139 VLOG(1) << object_path_.value() << ": Release";
140 }
141
NewConnection(const dbus::ObjectPath & device_path,scoped_ptr<dbus::FileDescriptor> fd,const BluetoothProfileServiceProvider::Delegate::Options & options,const ConfirmationCallback & callback)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
RequestDisconnection(const dbus::ObjectPath & device_path,const ConfirmationCallback & callback)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
Cancel()177 void BluetoothProfileChromeOS::Cancel() {
178 VLOG(1) << object_path_.value() << ": Cancel";
179 }
180
OnRegisterProfile(const ProfileCallback & callback)181 void BluetoothProfileChromeOS::OnRegisterProfile(
182 const ProfileCallback& callback) {
183 VLOG(1) << object_path_.value() << ": Profile registered";
184 callback.Run(this);
185 }
186
OnRegisterProfileError(const ProfileCallback & callback,const std::string & error_name,const std::string & error_message)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
OnUnregisterProfile()198 void BluetoothProfileChromeOS::OnUnregisterProfile() {
199 VLOG(1) << object_path_.value() << ": Profile unregistered";
200 object_path_ = dbus::ObjectPath("");
201 delete this;
202 }
203
OnUnregisterProfileError(const std::string & error_name,const std::string & error_message)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
GetAdapter(const dbus::ObjectPath & device_path,const BluetoothProfileServiceProvider::Delegate::Options & options,const ConfirmationCallback & callback,scoped_ptr<dbus::FileDescriptor> fd)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
OnGetAdapter(const dbus::ObjectPath & device_path,const BluetoothProfileServiceProvider::Delegate::Options & options,const ConfirmationCallback & callback,scoped_ptr<dbus::FileDescriptor> fd,scoped_refptr<BluetoothAdapter> adapter)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