blob: 704b68c54b7354d1ff80489621193505cc2463cd [file] [log] [blame]
[email protected]627f4f42013-06-12 14:47:321// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]e882d2c2013-05-09 03:49:182// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]627f4f42013-06-12 14:47:325#include "device/bluetooth/bluetooth_profile_chromeos.h"
[email protected]e882d2c2013-05-09 03:49:186
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"
[email protected]2a9ec0e2013-07-17 23:00:3015#include "base/message_loop/message_loop.h"
[email protected]0d8db082013-06-11 07:27:0116#include "base/strings/string_util.h"
[email protected]e882d2c2013-05-09 03:49:1817#include "base/task_runner_util.h"
18#include "base/threading/thread_restrictions.h"
19#include "base/threading/worker_pool.h"
[email protected]627f4f42013-06-12 14:47:3220#include "chromeos/dbus/bluetooth_profile_manager_client.h"
21#include "chromeos/dbus/bluetooth_profile_service_provider.h"
[email protected]e882d2c2013-05-09 03:49:1822#include "chromeos/dbus/dbus_thread_manager.h"
[email protected]e882d2c2013-05-09 03:49:1823#include "dbus/bus.h"
24#include "dbus/file_descriptor.h"
25#include "dbus/object_path.h"
[email protected]627f4f42013-06-12 14:47:3226#include "device/bluetooth/bluetooth_adapter_chromeos.h"
[email protected]e882d2c2013-05-09 03:49:1827#include "device/bluetooth/bluetooth_adapter_factory.h"
28#include "device/bluetooth/bluetooth_device.h"
[email protected]627f4f42013-06-12 14:47:3229#include "device/bluetooth/bluetooth_device_chromeos.h"
[email protected]e882d2c2013-05-09 03:49:1830#include "device/bluetooth/bluetooth_profile.h"
31#include "device/bluetooth/bluetooth_socket.h"
[email protected]627f4f42013-06-12 14:47:3232#include "device/bluetooth/bluetooth_socket_chromeos.h"
[email protected]67ab21b2014-03-12 10:12:4633#include "third_party/cros_system_api/dbus/service_constants.h"
[email protected]e882d2c2013-05-09 03:49:1834
35using device::BluetoothAdapter;
36using device::BluetoothAdapterFactory;
37using device::BluetoothDevice;
38using device::BluetoothProfile;
39using device::BluetoothSocket;
40
41namespace {
42
43// Check the validity of a file descriptor received from D-Bus. Must be run
44// on a thread where i/o is permitted.
45scoped_ptr<dbus::FileDescriptor> CheckValidity(
46 scoped_ptr<dbus::FileDescriptor> fd) {
47 base::ThreadRestrictions::AssertIOAllowed();
48 fd->CheckValidity();
49 return fd.Pass();
50}
51
52} // namespace
53
54
55namespace chromeos {
56
[email protected]627f4f42013-06-12 14:47:3257BluetoothProfileChromeOS::BluetoothProfileChromeOS()
[email protected]e882d2c2013-05-09 03:49:1858 : weak_ptr_factory_(this) {
59}
60
[email protected]627f4f42013-06-12 14:47:3261BluetoothProfileChromeOS::~BluetoothProfileChromeOS() {
[email protected]e882d2c2013-05-09 03:49:1862 DCHECK(object_path_.value().empty());
63 DCHECK(profile_.get() == NULL);
[email protected]67ab21b2014-03-12 10:12:4664
65 if (adapter_.get()) {
66 adapter_->RemoveObserver(this);
67 adapter_ = NULL;
68 }
[email protected]e882d2c2013-05-09 03:49:1869}
70
[email protected]627f4f42013-06-12 14:47:3271void BluetoothProfileChromeOS::Init(
[email protected]e882d2c2013-05-09 03:49:1872 const std::string& uuid,
73 const device::BluetoothProfile::Options& options,
74 const ProfileCallback& callback) {
75 DCHECK(object_path_.value().empty());
76 DCHECK(profile_.get() == NULL);
77
78 if (!BluetoothDevice::IsUUIDValid(uuid)) {
79 callback.Run(NULL);
80 return;
81 }
82
83 uuid_ = uuid;
84
[email protected]67ab21b2014-03-12 10:12:4685 options_.name = options.name;
86 options_.service = uuid;
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;
[email protected]e882d2c2013-05-09 03:49:1894
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;
[email protected]466c9862013-12-03 22:05:2898 base::ReplaceChars(uuid, ":-", "_", &uuid_path);
[email protected]e882d2c2013-05-09 03:49:1899
100 object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
101 uuid_path);
102
103 dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
[email protected]627f4f42013-06-12 14:47:32104 profile_.reset(BluetoothProfileServiceProvider::Create(
[email protected]e882d2c2013-05-09 03:49:18105 system_bus, object_path_, this));
106 DCHECK(profile_.get());
107
[email protected]67ab21b2014-03-12 10:12:46108 // Now the profile object is registered we need an adapter to register it
109 // with.
110 BluetoothAdapterFactory::GetAdapter(
111 base::Bind(&BluetoothProfileChromeOS::OnGetAdapter,
112 weak_ptr_factory_.GetWeakPtr(),
113 callback));
[email protected]e882d2c2013-05-09 03:49:18114}
115
[email protected]627f4f42013-06-12 14:47:32116void BluetoothProfileChromeOS::Unregister() {
[email protected]e882d2c2013-05-09 03:49:18117 DCHECK(!object_path_.value().empty());
118 DCHECK(profile_.get());
119
120 profile_.reset();
121
122 VLOG(1) << object_path_.value() << ": Unregister profile";
[email protected]627f4f42013-06-12 14:47:32123 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
[email protected]e882d2c2013-05-09 03:49:18124 UnregisterProfile(
125 object_path_,
[email protected]627f4f42013-06-12 14:47:32126 base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfile,
127 weak_ptr_factory_.GetWeakPtr()),
128 base::Bind(&BluetoothProfileChromeOS::OnUnregisterProfileError,
129 weak_ptr_factory_.GetWeakPtr()));
[email protected]e882d2c2013-05-09 03:49:18130}
131
[email protected]627f4f42013-06-12 14:47:32132void BluetoothProfileChromeOS::SetConnectionCallback(
[email protected]e882d2c2013-05-09 03:49:18133 const ConnectionCallback& callback) {
134 connection_callback_ = callback;
135}
136
[email protected]67ab21b2014-03-12 10:12:46137void BluetoothProfileChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter,
138 bool present) {
139 if (!present)
140 return;
141
142 VLOG(1) << object_path_.value() << ": Register profile";
143 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
144 RegisterProfile(
145 object_path_,
146 uuid_,
147 options_,
148 base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfile,
149 weak_ptr_factory_.GetWeakPtr()),
150 base::Bind(&BluetoothProfileChromeOS::OnInternalRegisterProfileError,
151 weak_ptr_factory_.GetWeakPtr()));
152}
153
154void BluetoothProfileChromeOS::OnGetAdapter(
155 const ProfileCallback& callback,
156 scoped_refptr<device::BluetoothAdapter> adapter) {
157 DCHECK(!adapter_.get());
158 adapter_ = adapter;
159 adapter_->AddObserver(this);
160
161 VLOG(1) << object_path_.value() << ": Register profile";
162 DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
163 RegisterProfile(
164 object_path_,
165 uuid_,
166 options_,
167 base::Bind(&BluetoothProfileChromeOS::OnRegisterProfile,
168 weak_ptr_factory_.GetWeakPtr(),
169 callback),
170 base::Bind(&BluetoothProfileChromeOS::OnRegisterProfileError,
171 weak_ptr_factory_.GetWeakPtr(),
172 callback));
173}
174
[email protected]627f4f42013-06-12 14:47:32175void BluetoothProfileChromeOS::Release() {
[email protected]e882d2c2013-05-09 03:49:18176 VLOG(1) << object_path_.value() << ": Release";
177}
178
[email protected]627f4f42013-06-12 14:47:32179void BluetoothProfileChromeOS::NewConnection(
[email protected]e882d2c2013-05-09 03:49:18180 const dbus::ObjectPath& device_path,
181 scoped_ptr<dbus::FileDescriptor> fd,
[email protected]627f4f42013-06-12 14:47:32182 const BluetoothProfileServiceProvider::Delegate::Options& options,
[email protected]e882d2c2013-05-09 03:49:18183 const ConfirmationCallback& callback) {
184 VLOG(1) << object_path_.value() << ": New connection from device: "
[email protected]5fbbea62014-02-26 20:07:33185 << device_path.value();
[email protected]e882d2c2013-05-09 03:49:18186 if (connection_callback_.is_null()) {
187 callback.Run(REJECTED);
188 return;
189 }
190
191 // Punt descriptor validity check to a worker thread where i/o is permitted;
[email protected]67ab21b2014-03-12 10:12:46192 // on return we'll call the connection callback.
[email protected]e882d2c2013-05-09 03:49:18193 //
194 // base::Passed is used to take ownership of the file descriptor during the
[email protected]67ab21b2014-03-12 10:12:46195 // CheckValidity() call and pass that ownership to callback.
[email protected]e882d2c2013-05-09 03:49:18196 base::PostTaskAndReplyWithResult(
[email protected]144b6c42013-06-14 07:30:38197 base::WorkerPool::GetTaskRunner(false).get(),
[email protected]e882d2c2013-05-09 03:49:18198 FROM_HERE,
199 base::Bind(&CheckValidity, base::Passed(&fd)),
[email protected]67ab21b2014-03-12 10:12:46200 base::Bind(&BluetoothProfileChromeOS::OnCheckValidity,
[email protected]e882d2c2013-05-09 03:49:18201 weak_ptr_factory_.GetWeakPtr(),
202 device_path,
203 options,
204 callback));
205}
206
[email protected]627f4f42013-06-12 14:47:32207void BluetoothProfileChromeOS::RequestDisconnection(
[email protected]e882d2c2013-05-09 03:49:18208 const dbus::ObjectPath& device_path,
209 const ConfirmationCallback& callback) {
210 VLOG(1) << object_path_.value() << ": Request disconnection";
211 callback.Run(SUCCESS);
212}
213
[email protected]627f4f42013-06-12 14:47:32214void BluetoothProfileChromeOS::Cancel() {
[email protected]e882d2c2013-05-09 03:49:18215 VLOG(1) << object_path_.value() << ": Cancel";
216}
217
[email protected]67ab21b2014-03-12 10:12:46218void BluetoothProfileChromeOS::OnInternalRegisterProfile() {
219 VLOG(1) << object_path_.value() << ": Profile registered";
220}
221
222void 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
226 // initialization.
227 if (error_name == bluetooth_profile_manager::kErrorAlreadyExists)
228 return;
229
230 LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
231 << error_name << ": " << error_message;
232}
233
[email protected]627f4f42013-06-12 14:47:32234void BluetoothProfileChromeOS::OnRegisterProfile(
[email protected]e882d2c2013-05-09 03:49:18235 const ProfileCallback& callback) {
236 VLOG(1) << object_path_.value() << ": Profile registered";
237 callback.Run(this);
238}
239
[email protected]627f4f42013-06-12 14:47:32240void BluetoothProfileChromeOS::OnRegisterProfileError(
[email protected]e882d2c2013-05-09 03:49:18241 const ProfileCallback& callback,
242 const std::string& error_name,
243 const std::string& error_message) {
[email protected]67ab21b2014-03-12 10:12:46244 // 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)
247 return;
248
[email protected]e882d2c2013-05-09 03:49:18249 LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
250 << error_name << ": " << error_message;
251 callback.Run(NULL);
[email protected]e882d2c2013-05-09 03:49:18252}
253
[email protected]627f4f42013-06-12 14:47:32254void BluetoothProfileChromeOS::OnUnregisterProfile() {
[email protected]e882d2c2013-05-09 03:49:18255 VLOG(1) << object_path_.value() << ": Profile unregistered";
256 object_path_ = dbus::ObjectPath("");
[email protected]e882d2c2013-05-09 03:49:18257 delete this;
258}
259
[email protected]627f4f42013-06-12 14:47:32260void BluetoothProfileChromeOS::OnUnregisterProfileError(
[email protected]e882d2c2013-05-09 03:49:18261 const std::string& error_name,
262 const std::string& error_message) {
[email protected]67ab21b2014-03-12 10:12:46263 // It's okay if the profile didn't exist, it means we never saw an adapter.
264 if (error_name == bluetooth_profile_manager::kErrorDoesNotExist)
265 return;
266
[email protected]e882d2c2013-05-09 03:49:18267 LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: "
268 << error_name << ": " << error_message;
269 object_path_ = dbus::ObjectPath("");
[email protected]e882d2c2013-05-09 03:49:18270 delete this;
271}
272
[email protected]67ab21b2014-03-12 10:12:46273void BluetoothProfileChromeOS::OnCheckValidity(
[email protected]e882d2c2013-05-09 03:49:18274 const dbus::ObjectPath& device_path,
[email protected]627f4f42013-06-12 14:47:32275 const BluetoothProfileServiceProvider::Delegate::Options& options,
[email protected]e882d2c2013-05-09 03:49:18276 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);
281 return;
282 }
283
[email protected]e882d2c2013-05-09 03:49:18284 callback.Run(SUCCESS);
285
[email protected]627f4f42013-06-12 14:47:32286 BluetoothDeviceChromeOS* device =
[email protected]67ab21b2014-03-12 10:12:46287 static_cast<BluetoothAdapterChromeOS*>(adapter_.get())->
[email protected]e882d2c2013-05-09 03:49:18288 GetDeviceWithPath(device_path);
289 DCHECK(device);
290
291 scoped_refptr<BluetoothSocket> socket((
[email protected]627f4f42013-06-12 14:47:32292 BluetoothSocketChromeOS::Create(fd.get())));
[email protected]e882d2c2013-05-09 03:49:18293 connection_callback_.Run(device, socket);
294}
295
296} // namespace chromeos