OLD | NEW |
| (Empty) |
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 #include "device/bluetooth/bluetooth_socket_thread.h" | |
34 #include "third_party/cros_system_api/dbus/service_constants.h" | |
35 | |
36 using device::BluetoothAdapter; | |
37 using device::BluetoothAdapterFactory; | |
38 using device::BluetoothDevice; | |
39 using device::BluetoothProfile; | |
40 using device::BluetoothSocket; | |
41 | |
42 namespace { | |
43 | |
44 // Check the validity of a file descriptor received from D-Bus. Must be run | |
45 // on a thread where i/o is permitted. | |
46 scoped_ptr<dbus::FileDescriptor> CheckValidity( | |
47 scoped_ptr<dbus::FileDescriptor> fd) { | |
48 base::ThreadRestrictions::AssertIOAllowed(); | |
49 fd->CheckValidity(); | |
50 return fd.Pass(); | |
51 } | |
52 | |
53 } // namespace | |
54 | |
55 | |
56 namespace chromeos { | |
57 | |
58 BluetoothProfileChromeOS::BluetoothProfileChromeOS( | |
59 scoped_refptr<base::SequencedTaskRunner> ui_task_runner, | |
60 scoped_refptr<device::BluetoothSocketThread> socket_thread) | |
61 : ui_task_runner_(ui_task_runner), | |
62 socket_thread_(socket_thread), | |
63 weak_ptr_factory_(this) { | |
64 } | |
65 | |
66 BluetoothProfileChromeOS::~BluetoothProfileChromeOS() { | |
67 DCHECK(object_path_.value().empty()); | |
68 DCHECK(profile_.get() == NULL); | |
69 | |
70 if (adapter_.get()) { | |
71 adapter_->RemoveObserver(this); | |
72 adapter_ = NULL; | |
73 } | |
74 } | |
75 | |
76 void BluetoothProfileChromeOS::Init( | |
77 const device::BluetoothUUID& uuid, | |
78 const device::BluetoothProfile::Options& options, | |
79 const ProfileCallback& callback) { | |
80 DCHECK(object_path_.value().empty()); | |
81 DCHECK(profile_.get() == NULL); | |
82 | |
83 if (!uuid.IsValid()) { | |
84 callback.Run(NULL); | |
85 return; | |
86 } | |
87 | |
88 uuid_ = uuid; | |
89 | |
90 options_.name = options.name; | |
91 options_.service = uuid.canonical_value(); | |
92 options_.channel = options.channel; | |
93 options_.psm = options.psm; | |
94 options_.require_authentication = options.require_authentication; | |
95 options_.require_authorization = options.require_authorization; | |
96 options_.auto_connect = options.auto_connect; | |
97 options_.version = options.version; | |
98 options_.features = options.features; | |
99 | |
100 // The object path is relatively meaningless, but has to be unique, so we | |
101 // use the UUID of the profile. | |
102 std::string uuid_path; | |
103 base::ReplaceChars(uuid.canonical_value(), ":-", "_", &uuid_path); | |
104 | |
105 object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" + | |
106 uuid_path); | |
107 | |
108 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); | |
109 profile_.reset(BluetoothProfileServiceProvider::Create( | |
110 system_bus, object_path_, this)); | |
111 DCHECK(profile_.get()); | |
112 | |
113 // Now the profile object is registered we need an adapter to register it | |
114 // with. | |
115 BluetoothAdapterFactory::GetAdapter( | |
116 base::Bind(&BluetoothProfileChromeOS::OnGetAdapter, | |
117 weak_ptr_factory_.GetWeakPtr(), | |
118 callback)); | |
119 } | |
120 | |
121 void BluetoothProfileChromeOS::Unregister() { | |
122 DCHECK(!object_path_.value().empty()); | |
123 DCHECK(profile_.get()); | |
124 | |
125 profile_.reset(); | |
126 | |
127 VLOG(1) << object_path_.value() << ": Unregister profile"; | |
128 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> | |
129 UnregisterProfile( | |
130 object_path_, | |
131 base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfile, | |
132 weak_ptr_factory_.GetWeakPtr()), | |
133 base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfileError, | |
134 weak_ptr_factory_.GetWeakPtr())); | |
135 } | |
136 | |
137 void BluetoothProfileChromeOS::SetConnectionCallback( | |
138 const ConnectionCallback& callback) { | |
139 connection_callback_ = callback; | |
140 } | |
141 | |
142 void BluetoothProfileChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter, | |
143 bool present) { | |
144 if (!present) | |
145 return; | |
146 | |
147 VLOG(1) << object_path_.value() << ": Register profile"; | |
148 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> | |
149 RegisterProfile( | |
150 object_path_, | |
151 uuid_.canonical_value(), | |
152 options_, | |
153 base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfile, | |
154 weak_ptr_factory_.GetWeakPtr()), | |
155 base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfileError, | |
156 weak_ptr_factory_.GetWeakPtr())); | |
157 } | |
158 | |
159 void BluetoothProfileChromeOS::OnGetAdapter( | |
160 const ProfileCallback& callback, | |
161 scoped_refptr<device::BluetoothAdapter> adapter) { | |
162 DCHECK(!adapter_.get()); | |
163 adapter_ = adapter; | |
164 adapter_->AddObserver(this); | |
165 | |
166 VLOG(1) << object_path_.value() << ": Register profile"; | |
167 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()-> | |
168 RegisterProfile( | |
169 object_path_, | |
170 uuid_.canonical_value(), | |
171 options_, | |
172 base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile, | |
173 weak_ptr_factory_.GetWeakPtr(), | |
174 callback), | |
175 base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError, | |
176 weak_ptr_factory_.GetWeakPtr(), | |
177 callback)); | |
178 } | |
179 | |
180 void BluetoothProfileChromeOS::Released() { | |
181 VLOG(1) << object_path_.value() << ": Release"; | |
182 } | |
183 | |
184 void BluetoothProfileChromeOS::NewConnection( | |
185 const dbus::ObjectPath& device_path, | |
186 scoped_ptr<dbus::FileDescriptor> fd, | |
187 const BluetoothProfileServiceProvider::Delegate::Options& options, | |
188 const ConfirmationCallback& callback) { | |
189 VLOG(1) << object_path_.value() << ": New connection from device: " | |
190 << device_path.value(); | |
191 if (connection_callback_.is_null()) { | |
192 callback.Run(REJECTED); | |
193 return; | |
194 } | |
195 | |
196 // Punt descriptor validity check to a worker thread where i/o is permitted; | |
197 // on return we'll call the connection callback. | |
198 // | |
199 // base::Passed is used to take ownership of the file descriptor during the | |
200 // CheckValidity() call and pass that ownership to callback. | |
201 base::PostTaskAndReplyWithResult( | |
202 base::WorkerPool::GetTaskRunner(false).get(), | |
203 FROM_HERE, | |
204 base::Bind(&CheckValidity, base::Passed(&fd)), | |
205 base::Bind(&BluetoothProfileChromeOS::OnCheckValidity, | |
206 weak_ptr_factory_.GetWeakPtr(), | |
207 device_path, | |
208 options, | |
209 callback)); | |
210 } | |
211 | |
212 void BluetoothProfileChromeOS::RequestDisconnection( | |
213 const dbus::ObjectPath& device_path, | |
214 const ConfirmationCallback& callback) { | |
215 VLOG(1) << object_path_.value() << ": Request disconnection"; | |
216 callback.Run(SUCCESS); | |
217 } | |
218 | |
219 void BluetoothProfileChromeOS::Cancel() { | |
220 VLOG(1) << object_path_.value() << ": Cancel"; | |
221 } | |
222 | |
223 void BluetoothProfileChromeOS::OnInternalRegisterProfile() { | |
224 VLOG(1) << object_path_.value() << ": Profile registered"; | |
225 } | |
226 | |
227 void BluetoothProfileChromeOS::OnInternalRegisterProfileError( | |
228 const std::string& error_name, | |
229 const std::string& error_message) { | |
230 // It's okay if the profile already exists, it means we registered it on | |
231 // initialization. | |
232 if (error_name == bluetooth_profile_manager::kErrorAlreadyExists) | |
233 return; | |
234 | |
235 LOG(WARNING) << object_path_.value() << ": Failed to register profile: " | |
236 << error_name << ": " << error_message; | |
237 } | |
238 | |
239 void BluetoothProfileChromeOS::OnRegisterProfile( | |
240 const ProfileCallback& callback) { | |
241 VLOG(1) << object_path_.value() << ": Profile registered"; | |
242 callback.Run(this); | |
243 } | |
244 | |
245 void BluetoothProfileChromeOS::OnRegisterProfileError( | |
246 const ProfileCallback& callback, | |
247 const std::string& error_name, | |
248 const std::string& error_message) { | |
249 // It's okay if the profile already exists, it means we registered it when | |
250 // we first saw the adapter. | |
251 if (error_name == bluetooth_profile_manager::kErrorAlreadyExists) | |
252 return; | |
253 | |
254 LOG(WARNING) << object_path_.value() << ": Failed to register profile: " | |
255 << error_name << ": " << error_message; | |
256 callback.Run(NULL); | |
257 } | |
258 | |
259 void BluetoothProfileChromeOS::OnUnregisterProfile() { | |
260 VLOG(1) << object_path_.value() << ": Profile unregistered"; | |
261 object_path_ = dbus::ObjectPath(""); | |
262 delete this; | |
263 } | |
264 | |
265 void BluetoothProfileChromeOS::OnUnregisterProfileError( | |
266 const std::string& error_name, | |
267 const std::string& error_message) { | |
268 // It's okay if the profile didn't exist, it means we never saw an adapter. | |
269 if (error_name == bluetooth_profile_manager::kErrorDoesNotExist) | |
270 return; | |
271 | |
272 LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: " | |
273 << error_name << ": " << error_message; | |
274 object_path_ = dbus::ObjectPath(""); | |
275 delete this; | |
276 } | |
277 | |
278 void BluetoothProfileChromeOS::OnCheckValidity( | |
279 const dbus::ObjectPath& device_path, | |
280 const BluetoothProfileServiceProvider::Delegate::Options& options, | |
281 const ConfirmationCallback& callback, | |
282 scoped_ptr<dbus::FileDescriptor> fd) { | |
283 VLOG(1) << object_path_.value() << ": Validity check complete"; | |
284 if (!fd->is_valid()) { | |
285 callback.Run(REJECTED); | |
286 return; | |
287 } | |
288 | |
289 scoped_refptr<BluetoothSocketChromeOS> socket = | |
290 BluetoothSocketChromeOS::CreateBluetoothSocket( | |
291 ui_task_runner_, | |
292 socket_thread_, | |
293 NULL, | |
294 net::NetLog::Source()); | |
295 socket->Connect(fd.Pass(), | |
296 base::Bind(&BluetoothProfileChromeOS::OnConnect, | |
297 weak_ptr_factory_.GetWeakPtr(), | |
298 device_path, | |
299 socket, | |
300 callback), | |
301 base::Bind(&BluetoothProfileChromeOS::OnConnectError, | |
302 weak_ptr_factory_.GetWeakPtr(), | |
303 callback)); | |
304 } | |
305 | |
306 void BluetoothProfileChromeOS::OnConnect( | |
307 const dbus::ObjectPath& device_path, | |
308 scoped_refptr<BluetoothSocketChromeOS> socket, | |
309 const ConfirmationCallback& callback) { | |
310 VLOG(1) << object_path_.value() << ": Profile connection complete"; | |
311 | |
312 BluetoothDeviceChromeOS* device = | |
313 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())-> | |
314 GetDeviceWithPath(device_path); | |
315 DCHECK(device); | |
316 | |
317 connection_callback_.Run(device, socket); | |
318 callback.Run(SUCCESS); | |
319 } | |
320 | |
321 void BluetoothProfileChromeOS::OnConnectError( | |
322 const ConfirmationCallback& callback, | |
323 const std::string& error_message) { | |
324 VLOG(1) << object_path_.value() << ": Profile connection failed: " | |
325 << error_message; | |
326 | |
327 callback.Run(REJECTED); | |
328 } | |
329 | |
330 } // namespace chromeos | |
OLD | NEW |