summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
authorjamuraa <jamuraa@chromium.org>2015-01-29 16:31:56 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-30 00:33:39 +0000
commitc56186ac2901c99349cbb4b4a6b8aa0ff8088c4d (patch)
treeb1e6b79808e3c05fd1ab5abf3144412edaf2f9c3 /device
parent224af1f65be9b9e8b11d485adc120e8d488a9fe3 (diff)
downloadchromium_src-c56186ac2901c99349cbb4b4a6b8aa0ff8088c4d.zip
chromium_src-c56186ac2901c99349cbb4b4a6b8aa0ff8088c4d.tar.gz
chromium_src-c56186ac2901c99349cbb4b4a6b8aa0ff8088c4d.tar.bz2
Manage profiles in BluetoothAdapter on ChromeOS
Profiles in bluez are not specific to a device. When client code tries to connect to two different devices, only one profile is created, managed by BluetoothAdapterChromeOS. dbus messages are multiplexed based on the device desired using new class BluetoothAdapterProfileChromeOS. BUG=chromium:421207 Review URL: https://codereview.chromium.org/851123002 Cr-Commit-Position: refs/heads/master@{#313837}
Diffstat (limited to 'device')
-rw-r--r--device/bluetooth/BUILD.gn2
-rw-r--r--device/bluetooth/bluetooth.gyp2
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.cc71
-rw-r--r--device/bluetooth/bluetooth_adapter_chromeos.h45
-rw-r--r--device/bluetooth/bluetooth_adapter_profile_chromeos.cc165
-rw-r--r--device/bluetooth/bluetooth_adapter_profile_chromeos.h101
-rw-r--r--device/bluetooth/bluetooth_adapter_profile_chromeos_unittest.cc297
-rw-r--r--device/bluetooth/bluetooth_device_chromeos.h3
-rw-r--r--device/bluetooth/bluetooth_socket_chromeos.cc246
-rw-r--r--device/bluetooth/bluetooth_socket_chromeos.h35
-rw-r--r--device/bluetooth/bluetooth_socket_chromeos_unittest.cc29
-rw-r--r--device/device_tests.gyp1
12 files changed, 833 insertions, 164 deletions
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 056a5fa..d8bc665 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -27,6 +27,8 @@ component("bluetooth") {
"bluetooth_adapter_factory.h",
"bluetooth_adapter_mac.h",
"bluetooth_adapter_mac.mm",
+ "bluetooth_adapter_profile_chromeos.cc",
+ "bluetooth_adapter_profile_chromeos.h",
"bluetooth_adapter_win.cc",
"bluetooth_adapter_win.h",
"bluetooth_audio_sink.cc",
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index cec2180..30b9ffe 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -30,6 +30,8 @@
'bluetooth_adapter_factory.h',
'bluetooth_adapter_mac.h',
'bluetooth_adapter_mac.mm',
+ "bluetooth_adapter_profile_chromeos.cc",
+ "bluetooth_adapter_profile_chromeos.h",
'bluetooth_adapter_win.cc',
'bluetooth_adapter_win.h',
'bluetooth_audio_sink.cc',
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc
index 9bc4c55..252fa71b 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.cc
+++ b/device/bluetooth/bluetooth_adapter_chromeos.cc
@@ -20,6 +20,7 @@
#include "chromeos/dbus/bluetooth_device_client.h"
#include "chromeos/dbus/bluetooth_input_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
+#include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_chromeos.h"
#include "device/bluetooth/bluetooth_pairing_chromeos.h"
@@ -929,6 +930,76 @@ void BluetoothAdapterChromeOS::NotifyGattDescriptorValueChanged(
GattDescriptorValueChanged(this, descriptor, value));
}
+void BluetoothAdapterChromeOS::UseProfile(
+ const BluetoothUUID& uuid,
+ const dbus::ObjectPath& device_path,
+ const BluetoothProfileManagerClient::Options& options,
+ BluetoothProfileServiceProvider::Delegate* delegate,
+ const ProfileRegisteredCallback& success_callback,
+ const ErrorCompletionCallback& error_callback) {
+ DCHECK(delegate);
+
+ if (profiles_.find(uuid) != profiles_.end()) {
+ // TODO(jamuraa) check that the options are the same and error when they are
+ // not.
+ SetProfileDelegate(uuid, device_path, delegate, success_callback,
+ error_callback);
+ return;
+ }
+
+ profiles_[uuid] = BluetoothAdapterProfileChromeOS::Register(
+ this, uuid, options,
+ base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfile, this, uuid,
+ device_path, delegate, success_callback, error_callback),
+ base::Bind(&BluetoothAdapterChromeOS::OnRegisterProfileError, this, uuid,
+ error_callback));
+}
+
+void BluetoothAdapterChromeOS::ReleaseProfile(const BluetoothUUID& uuid) {
+ if (profiles_.find(uuid) != profiles_.end()) {
+ delete profiles_[uuid];
+ profiles_.erase(uuid);
+ }
+}
+
+void BluetoothAdapterChromeOS::OnRegisterProfile(
+ const BluetoothUUID& uuid,
+ const dbus::ObjectPath& device_path,
+ BluetoothProfileServiceProvider::Delegate* delegate,
+ const ProfileRegisteredCallback& success_callback,
+ const ErrorCompletionCallback& error_callback) {
+ SetProfileDelegate(uuid, device_path, delegate, success_callback,
+ error_callback);
+}
+
+bool BluetoothAdapterChromeOS::SetProfileDelegate(
+ const BluetoothUUID& uuid,
+ const dbus::ObjectPath& device_path,
+ BluetoothProfileServiceProvider::Delegate* delegate,
+ const ProfileRegisteredCallback& success_callback,
+ const ErrorCompletionCallback& error_callback) {
+ if (profiles_[uuid]->SetDelegate(device_path, delegate)) {
+ success_callback.Run(profiles_[uuid]);
+ return true;
+ }
+ // Already set
+ error_callback.Run(bluetooth_agent_manager::kErrorAlreadyExists);
+ return false;
+}
+
+void BluetoothAdapterChromeOS::OnRegisterProfileError(
+ const BluetoothUUID& uuid,
+ const ErrorCompletionCallback& error_callback,
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << object_path_.value()
+ << ": Failed to register profile: " << error_name << ": "
+ << error_message;
+ error_callback.Run(error_message);
+ delete profiles_[uuid];
+ profiles_.erase(uuid);
+}
+
void BluetoothAdapterChromeOS::OnSetDiscoverable(
const base::Closure& callback,
const ErrorCallback& error_callback,
diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h
index 5ee633f..dc9dd44 100644
--- a/device/bluetooth/bluetooth_adapter_chromeos.h
+++ b/device/bluetooth/bluetooth_adapter_chromeos.h
@@ -5,6 +5,7 @@
#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_CHROMEOS_H_
+#include <map>
#include <queue>
#include <string>
#include <utility>
@@ -16,6 +17,8 @@
#include "chromeos/dbus/bluetooth_agent_service_provider.h"
#include "chromeos/dbus/bluetooth_device_client.h"
#include "chromeos/dbus/bluetooth_input_client.h"
+#include "chromeos/dbus/bluetooth_profile_manager_client.h"
+#include "chromeos/dbus/bluetooth_profile_service_provider.h"
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_audio_sink.h"
@@ -29,6 +32,7 @@ class BluetoothSocketThread;
namespace chromeos {
class BluetoothChromeOSTest;
+class BluetoothAdapterProfileChromeOS;
class BluetoothDeviceChromeOS;
class BluetoothPairingChromeOS;
class BluetoothRemoteGattCharacteristicChromeOS;
@@ -44,6 +48,11 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS
public chromeos::BluetoothInputClient::Observer,
public chromeos::BluetoothAgentServiceProvider::Delegate {
public:
+ typedef base::Callback<void(const std::string& error_message)>
+ ErrorCompletionCallback;
+ typedef base::Callback<void(BluetoothAdapterProfileChromeOS* profile)>
+ ProfileRegisteredCallback;
+
static base::WeakPtr<BluetoothAdapter> CreateAdapter();
// BluetoothAdapter:
@@ -115,6 +124,23 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS
// Returns the object path of the adapter.
const dbus::ObjectPath& object_path() const { return object_path_; }
+ // Request a profile on the adapter for a custom service with a
+ // specific UUID for the device at |device_path| to be sent to |delegate|.
+ // If |device_path| is the empty string, incoming connections will be
+ // assigned to |delegate|. When the profile is
+ // successfully registered, |success_callback| will be called with a pointer
+ // to the profile which is managed by BluetoothAdapterChromeOS. On failure,
+ // |error_callback| will be called.
+ void UseProfile(const device::BluetoothUUID& uuid,
+ const dbus::ObjectPath& device_path,
+ const BluetoothProfileManagerClient::Options& options,
+ BluetoothProfileServiceProvider::Delegate* delegate,
+ const ProfileRegisteredCallback& success_callback,
+ const ErrorCompletionCallback& error_callback);
+
+ // Releases the profile associated with |uuid|
+ void ReleaseProfile(const device::BluetoothUUID& uuid);
+
protected:
// BluetoothAdapter:
void RemovePairingDelegateInternal(
@@ -235,6 +261,22 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS
const std::string& error_name,
const std::string& error_message);
+ // Called by dbus:: on completion of the D-Bus method to register a profile.
+ void OnRegisterProfile(const device::BluetoothUUID& uuid,
+ const dbus::ObjectPath& device_path,
+ BluetoothProfileServiceProvider::Delegate* delegate,
+ const ProfileRegisteredCallback& success_callback,
+ const ErrorCompletionCallback& error_callback);
+ bool SetProfileDelegate(const device::BluetoothUUID& uuid,
+ const dbus::ObjectPath& device_path,
+ BluetoothProfileServiceProvider::Delegate* delegate,
+ const ProfileRegisteredCallback& success_callback,
+ const ErrorCompletionCallback& error_callback);
+ void OnRegisterProfileError(const device::BluetoothUUID& uuid,
+ const ErrorCompletionCallback& error_callback,
+ const std::string& error_name,
+ const std::string& error_message);
+
// Processes the queued discovery requests. For each DiscoveryCallbackPair in
// the queue, this method will try to add a new discovery session. This method
// is called whenever a pending D-Bus call to start or stop discovery has
@@ -275,6 +317,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterChromeOS
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
scoped_refptr<device::BluetoothSocketThread> socket_thread_;
+ // The profiles we have registered with the bluetooth daemon.
+ std::map<device::BluetoothUUID, BluetoothAdapterProfileChromeOS*> profiles_;
+
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<BluetoothAdapterChromeOS> weak_ptr_factory_;
diff --git a/device/bluetooth/bluetooth_adapter_profile_chromeos.cc b/device/bluetooth/bluetooth_adapter_profile_chromeos.cc
new file mode 100644
index 0000000..74d84bf
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_profile_chromeos.cc
@@ -0,0 +1,165 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "chromeos/dbus/bluetooth_profile_service_provider.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "dbus/bus.h"
+#include "dbus/object_path.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+
+namespace chromeos {
+
+// static
+BluetoothAdapterProfileChromeOS* BluetoothAdapterProfileChromeOS::Register(
+ BluetoothAdapterChromeOS* adapter,
+ const device::BluetoothUUID& uuid,
+ const BluetoothProfileManagerClient::Options& options,
+ const base::Closure& success_callback,
+ const BluetoothProfileManagerClient::ErrorCallback& error_callback) {
+ DCHECK(adapter);
+
+ BluetoothAdapterProfileChromeOS* profile =
+ new BluetoothAdapterProfileChromeOS(adapter, uuid);
+
+ VLOG(1) << "Registering profile: " << profile->object_path().value();
+ DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->RegisterProfile(
+ profile->object_path(), uuid.canonical_value(), options, success_callback,
+ error_callback);
+
+ return profile;
+}
+
+BluetoothAdapterProfileChromeOS::BluetoothAdapterProfileChromeOS(
+ BluetoothAdapterChromeOS* adapter,
+ const device::BluetoothUUID& uuid)
+ : uuid_(uuid), adapter_(adapter), weak_ptr_factory_(this) {
+ std::string uuid_path;
+ base::ReplaceChars(uuid.canonical_value(), ":-", "_", &uuid_path);
+ object_path_ =
+ dbus::ObjectPath("/org/chromium/bluetooth_profile/" + uuid_path);
+
+ dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
+ profile_.reset(
+ BluetoothProfileServiceProvider::Create(system_bus, object_path_, this));
+ DCHECK(profile_.get());
+}
+
+BluetoothAdapterProfileChromeOS::~BluetoothAdapterProfileChromeOS() {
+ profile_.reset();
+}
+
+bool BluetoothAdapterProfileChromeOS::SetDelegate(
+ const dbus::ObjectPath& device_path,
+ BluetoothProfileServiceProvider::Delegate* delegate) {
+ DCHECK(delegate);
+ VLOG(1) << "SetDelegate: " << object_path_.value() << " dev "
+ << device_path.value();
+
+ if (delegates_.find(device_path.value()) != delegates_.end()) {
+ return false;
+ }
+
+ delegates_[device_path.value()] = delegate;
+ return true;
+}
+
+void BluetoothAdapterProfileChromeOS::RemoveDelegate(
+ const dbus::ObjectPath& device_path,
+ const base::Closure& unregistered_callback) {
+ VLOG(1) << object_path_.value() << " dev " << device_path.value()
+ << ": RemoveDelegate";
+
+ if (delegates_.find(device_path.value()) == delegates_.end())
+ return;
+
+ VLOG(1) << device_path.value() << " Delegate found";
+
+ delegates_.erase(device_path.value());
+
+ if (delegates_.size() != 0)
+ return;
+
+ // No users left, release the profile.
+ DBusThreadManager::Get()
+ ->GetBluetoothProfileManagerClient()
+ ->UnregisterProfile(
+ object_path_, unregistered_callback,
+ base::Bind(&BluetoothAdapterProfileChromeOS::OnUnregisterProfileError,
+ weak_ptr_factory_.GetWeakPtr(), unregistered_callback));
+}
+
+void BluetoothAdapterProfileChromeOS::OnUnregisterProfileError(
+ const base::Closure& unregistered_callback,
+ const std::string& error_name,
+ const std::string& error_message) {
+ LOG(WARNING) << this->object_path().value()
+ << ": Failed to unregister profile: " << error_name << ": "
+ << error_message;
+
+ unregistered_callback.Run();
+}
+
+// BluetoothProfileServiceProvider::Delegate:
+void BluetoothAdapterProfileChromeOS::Released() {
+ VLOG(1) << object_path_.value() << ": Release";
+}
+
+void BluetoothAdapterProfileChromeOS::NewConnection(
+ const dbus::ObjectPath& device_path,
+ scoped_ptr<dbus::FileDescriptor> fd,
+ const BluetoothProfileServiceProvider::Delegate::Options& options,
+ const ConfirmationCallback& callback) {
+ dbus::ObjectPath delegate_path = device_path;
+
+ if (delegates_.find(device_path.value()) == delegates_.end())
+ delegate_path = dbus::ObjectPath("");
+
+ if (delegates_.find(delegate_path.value()) == delegates_.end()) {
+ VLOG(1) << object_path_.value() << ": New connection for device "
+ << device_path.value() << " which has no delegates!";
+ callback.Run(REJECTED);
+ return;
+ }
+
+ delegates_[delegate_path.value()]->NewConnection(device_path, fd.Pass(),
+ options, callback);
+}
+
+void BluetoothAdapterProfileChromeOS::RequestDisconnection(
+ const dbus::ObjectPath& device_path,
+ const ConfirmationCallback& callback) {
+ dbus::ObjectPath delegate_path = device_path;
+
+ if (delegates_.find(device_path.value()) == delegates_.end())
+ delegate_path = dbus::ObjectPath("");
+
+ if (delegates_.find(delegate_path.value()) == delegates_.end()) {
+ VLOG(1) << object_path_.value() << ": RequestDisconnection for device "
+ << device_path.value() << " which has no delegates!";
+ return;
+ }
+
+ delegates_[delegate_path.value()]->RequestDisconnection(device_path,
+ callback);
+}
+
+void BluetoothAdapterProfileChromeOS::Cancel() {
+ // Cancel() should only go to a delegate accepting connections.
+ if (delegates_.find("") == delegates_.end()) {
+ VLOG(1) << object_path_.value() << ": Cancel with no delegate!";
+ return;
+ }
+
+ delegates_[""]->Cancel();
+}
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_adapter_profile_chromeos.h b/device/bluetooth/bluetooth_adapter_profile_chromeos.h
new file mode 100644
index 0000000..5f1edc2
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_profile_chromeos.h
@@ -0,0 +1,101 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_PROFILE_CHROMEOS_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_PROFILE_CHROMEOS_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chromeos/dbus/bluetooth_profile_manager_client.h"
+#include "chromeos/dbus/bluetooth_profile_service_provider.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_export.h"
+
+namespace device {
+class BluetoothUUID;
+} // namespace device
+
+namespace chromeos {
+
+// The BluetoothAdapterProfileChromeOS class implements a multiplexing
+// profile for custom Bluetooth services managed by a BluetoothAdapter.
+// Maintains a list of delegates which may serve the profile.
+// One delegate is allowed for each device.
+class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterProfileChromeOS
+ : public chromeos::BluetoothProfileServiceProvider::Delegate {
+ public:
+ // Registers a profile with the BlueZ server for |uuid| with the
+ // options |options|. Returns a newly allocated pointer, or nullptr
+ // if there was a problem.
+ static BluetoothAdapterProfileChromeOS* Register(
+ BluetoothAdapterChromeOS* adapter,
+ const device::BluetoothUUID& uuid,
+ const BluetoothProfileManagerClient::Options& options,
+ const base::Closure& success_callback,
+ const BluetoothProfileManagerClient::ErrorCallback& error_callback);
+
+ ~BluetoothAdapterProfileChromeOS() override;
+
+ // The object path of the profile.
+ const dbus::ObjectPath& object_path() const { return object_path_; }
+
+ // Add a delegate for a device associated with this profile.
+ // An empty |device_path| indicates a local listening service.
+ // Returns true if the delegate was set, and false if the |device_path|
+ // already had a delegate set.
+ bool SetDelegate(const dbus::ObjectPath& device_path,
+ BluetoothProfileServiceProvider::Delegate* delegate);
+
+ // Remove the delegate for a device. |unregistered_callback| will be called
+ // if this unregisters the profile.
+ void RemoveDelegate(const dbus::ObjectPath& device_path,
+ const base::Closure& unregistered_callback);
+
+ // Returns the number of delegates for this profile.
+ size_t DelegateCount() const { return delegates_.size(); }
+
+ private:
+ BluetoothAdapterProfileChromeOS(BluetoothAdapterChromeOS* adapter,
+ const device::BluetoothUUID& uuid);
+
+ // BluetoothProfileServiceProvider::Delegate:
+ void Released() override;
+ void NewConnection(
+ const dbus::ObjectPath& device_path,
+ scoped_ptr<dbus::FileDescriptor> fd,
+ const BluetoothProfileServiceProvider::Delegate::Options& options,
+ const ConfirmationCallback& callback) override;
+ void RequestDisconnection(const dbus::ObjectPath& device_path,
+ const ConfirmationCallback& callback) override;
+ void Cancel() override;
+
+ // Called by dbus:: on completion of the D-Bus method to unregister a profile.
+ void OnUnregisterProfileError(const base::Closure& unregistered_callback,
+ const std::string& error_name,
+ const std::string& error_message);
+
+ // List of delegates which this profile is multiplexing to.
+ std::map<std::string, BluetoothProfileServiceProvider::Delegate*> delegates_;
+
+ // The UUID that this profile represents.
+ const device::BluetoothUUID& uuid_;
+
+ // Registered dbus object path for this profile.
+ dbus::ObjectPath object_path_;
+
+ // Profile dbus object for receiving profile method calls from BlueZ
+ scoped_ptr<BluetoothProfileServiceProvider> profile_;
+
+ // Adapter that owns this profile.
+ BluetoothAdapterChromeOS* adapter_;
+
+ // Note: This should remain the last member so it'll be destroyed and
+ // invalidate its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<BluetoothAdapterProfileChromeOS> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterProfileChromeOS);
+};
+
+} // namespace chromeos
+
+#endif
diff --git a/device/bluetooth/bluetooth_adapter_profile_chromeos_unittest.cc b/device/bluetooth/bluetooth_adapter_profile_chromeos_unittest.cc
new file mode 100644
index 0000000..6b29dd2
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_profile_chromeos_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "chromeos/dbus/bluetooth_profile_service_provider.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_bluetooth_adapter_client.h"
+#include "chromeos/dbus/fake_bluetooth_agent_manager_client.h"
+#include "chromeos/dbus/fake_bluetooth_device_client.h"
+#include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using device::BluetoothAdapter;
+using device::BluetoothUUID;
+
+namespace {
+
+void DoNothingDBusErrorCallback(const std::string& error_name,
+ const std::string& error_message) {
+}
+
+} // namespace
+
+namespace chromeos {
+
+class BluetoothAdapterProfileChromeOSTest : public testing::Test {
+ public:
+ BluetoothAdapterProfileChromeOSTest()
+ : fake_delegate_paired_(FakeBluetoothDeviceClient::kPairedDevicePath),
+ fake_delegate_autopair_(FakeBluetoothDeviceClient::kLegacyAutopairPath),
+ fake_delegate_listen_(""),
+ profile_(nullptr),
+ success_callback_count_(0),
+ error_callback_count_(0) {}
+
+ void SetUp() override {
+ scoped_ptr<DBusThreadManagerSetter> dbus_setter =
+ DBusThreadManager::GetSetterForTesting();
+
+ dbus_setter->SetBluetoothAdapterClient(
+ scoped_ptr<BluetoothAdapterClient>(new FakeBluetoothAdapterClient));
+ dbus_setter->SetBluetoothAgentManagerClient(
+ scoped_ptr<BluetoothAgentManagerClient>(
+ new FakeBluetoothAgentManagerClient));
+ dbus_setter->SetBluetoothDeviceClient(
+ scoped_ptr<BluetoothDeviceClient>(new FakeBluetoothDeviceClient));
+ dbus_setter->SetBluetoothProfileManagerClient(
+ scoped_ptr<BluetoothProfileManagerClient>(
+ new FakeBluetoothProfileManagerClient));
+
+ // Grab a pointer to the adapter.
+ device::BluetoothAdapterFactory::GetAdapter(
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::AdapterCallback,
+ base::Unretained(this)));
+ ASSERT_TRUE(adapter_.get() != nullptr);
+ ASSERT_TRUE(adapter_->IsInitialized());
+ ASSERT_TRUE(adapter_->IsPresent());
+
+ // Turn on the adapter.
+ adapter_->SetPowered(true, base::Bind(&base::DoNothing),
+ base::Bind(&base::DoNothing));
+ ASSERT_TRUE(adapter_->IsPowered());
+ }
+
+ void TearDown() override {
+ adapter_ = nullptr;
+ DBusThreadManager::Shutdown();
+ }
+
+ void AdapterCallback(scoped_refptr<BluetoothAdapter> adapter) {
+ adapter_ = adapter;
+ }
+
+ class FakeDelegate
+ : public chromeos::BluetoothProfileServiceProvider::Delegate {
+ public:
+ FakeDelegate(std::string device_path) : connections_(0) {
+ device_path_ = dbus::ObjectPath(device_path);
+ }
+
+ // BluetoothProfileServiceProvider::Delegate:
+ void Released() override {
+ // noop
+ }
+
+ void NewConnection(
+ const dbus::ObjectPath& device_path,
+ scoped_ptr<dbus::FileDescriptor> fd,
+ const BluetoothProfileServiceProvider::Delegate::Options& options,
+ const ConfirmationCallback& callback) override {
+ VLOG(1) << "connection for " << device_path.value() << " on "
+ << device_path_.value();
+ ++connections_;
+ fd->CheckValidity();
+ close(fd->TakeValue());
+ callback.Run(SUCCESS);
+ if (device_path_.value() != "")
+ ASSERT_TRUE(device_path == device_path_);
+ }
+
+ void RequestDisconnection(const dbus::ObjectPath& device_path,
+ const ConfirmationCallback& callback) override {
+ VLOG(1) << "disconnect " << device_path.value();
+ ++disconnections_;
+ }
+
+ void Cancel() override {
+ VLOG(1) << "cancel";
+ // noop
+ }
+
+ unsigned int connections_;
+ unsigned int disconnections_;
+ dbus::ObjectPath device_path_;
+ };
+
+ FakeDelegate fake_delegate_paired_;
+ FakeDelegate fake_delegate_autopair_;
+ FakeDelegate fake_delegate_listen_;
+
+ BluetoothAdapterProfileChromeOS* profile_;
+
+ void DBusConnectSuccessCallback() { ++success_callback_count_; }
+
+ void DBusErrorCallback(const std::string& error_name,
+ const std::string& error_message) {
+ VLOG(1) << "DBus Connect Error: " << error_name << " - " << error_message;
+ ++error_callback_count_;
+ }
+
+ protected:
+ base::MessageLoop message_loop_;
+
+ scoped_refptr<BluetoothAdapter> adapter_;
+
+ unsigned int success_callback_count_;
+ unsigned int error_callback_count_;
+};
+
+TEST_F(BluetoothAdapterProfileChromeOSTest, DelegateCount) {
+ BluetoothUUID uuid(FakeBluetoothProfileManagerClient::kRfcommUuid);
+ BluetoothProfileManagerClient::Options options;
+
+ options.require_authentication.reset(new bool(false));
+
+ profile_ = BluetoothAdapterProfileChromeOS::Register(
+ static_cast<BluetoothAdapterChromeOS*>(adapter_.get()), uuid, options,
+ base::Bind(&base::DoNothing), base::Bind(&DoNothingDBusErrorCallback));
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_TRUE(profile_);
+
+ EXPECT_EQ(0U, profile_->DelegateCount());
+
+ profile_->SetDelegate(fake_delegate_paired_.device_path_,
+ &fake_delegate_paired_);
+
+ EXPECT_EQ(1U, profile_->DelegateCount());
+
+ profile_->RemoveDelegate(fake_delegate_autopair_.device_path_,
+ base::Bind(&base::DoNothing));
+
+ EXPECT_EQ(1U, profile_->DelegateCount());
+
+ profile_->RemoveDelegate(fake_delegate_paired_.device_path_,
+ base::Bind(&base::DoNothing));
+
+ EXPECT_EQ(0U, profile_->DelegateCount());
+
+ delete profile_;
+};
+
+TEST_F(BluetoothAdapterProfileChromeOSTest, BlackHole) {
+ BluetoothUUID uuid(FakeBluetoothProfileManagerClient::kRfcommUuid);
+ BluetoothProfileManagerClient::Options options;
+
+ options.require_authentication.reset(new bool(false));
+
+ profile_ = BluetoothAdapterProfileChromeOS::Register(
+ static_cast<BluetoothAdapterChromeOS*>(adapter_.get()), uuid, options,
+ base::Bind(
+ &BluetoothAdapterProfileChromeOSTest::DBusConnectSuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_TRUE(profile_);
+ EXPECT_EQ(1U, success_callback_count_);
+ EXPECT_EQ(0U, error_callback_count_);
+
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPairedDevicePath),
+ FakeBluetoothProfileManagerClient::kRfcommUuid,
+ base::Bind(
+ &BluetoothAdapterProfileChromeOSTest::DBusConnectSuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(1U, success_callback_count_);
+ EXPECT_EQ(1U, error_callback_count_);
+
+ EXPECT_EQ(0U, fake_delegate_paired_.connections_);
+
+ delete profile_;
+};
+
+TEST_F(BluetoothAdapterProfileChromeOSTest, Routing) {
+ BluetoothUUID uuid(FakeBluetoothProfileManagerClient::kRfcommUuid);
+ BluetoothProfileManagerClient::Options options;
+
+ options.require_authentication.reset(new bool(false));
+
+ profile_ = BluetoothAdapterProfileChromeOS::Register(
+ static_cast<BluetoothAdapterChromeOS*>(adapter_.get()), uuid, options,
+ base::Bind(
+ &BluetoothAdapterProfileChromeOSTest::DBusConnectSuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.RunUntilIdle();
+
+ ASSERT_TRUE(profile_);
+
+ profile_->SetDelegate(fake_delegate_paired_.device_path_,
+ &fake_delegate_paired_);
+ profile_->SetDelegate(fake_delegate_autopair_.device_path_,
+ &fake_delegate_autopair_);
+ profile_->SetDelegate(fake_delegate_listen_.device_path_,
+ &fake_delegate_listen_);
+
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kPairedDevicePath),
+ FakeBluetoothProfileManagerClient::kRfcommUuid,
+ base::Bind(
+ &BluetoothAdapterProfileChromeOSTest::DBusConnectSuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(2U, success_callback_count_);
+ EXPECT_EQ(0U, error_callback_count_);
+
+ EXPECT_EQ(1U, fake_delegate_paired_.connections_);
+
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kLegacyAutopairPath),
+ FakeBluetoothProfileManagerClient::kRfcommUuid,
+ base::Bind(
+ &BluetoothAdapterProfileChromeOSTest::DBusConnectSuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(3U, success_callback_count_);
+ EXPECT_EQ(0U, error_callback_count_);
+
+ EXPECT_EQ(1U, fake_delegate_autopair_.connections_);
+
+ // Incoming connections look the same from BlueZ.
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
+ dbus::ObjectPath(FakeBluetoothDeviceClient::kDisplayPinCodePath),
+ FakeBluetoothProfileManagerClient::kRfcommUuid,
+ base::Bind(
+ &BluetoothAdapterProfileChromeOSTest::DBusConnectSuccessCallback,
+ base::Unretained(this)),
+ base::Bind(&BluetoothAdapterProfileChromeOSTest::DBusErrorCallback,
+ base::Unretained(this)));
+
+ message_loop_.RunUntilIdle();
+
+ EXPECT_EQ(4U, success_callback_count_);
+ EXPECT_EQ(0U, error_callback_count_);
+
+ EXPECT_EQ(1U, fake_delegate_listen_.connections_);
+
+ delete profile_;
+};
+
+} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_device_chromeos.h b/device/bluetooth/bluetooth_device_chromeos.h
index 6b9afc9..236b950 100644
--- a/device/bluetooth/bluetooth_device_chromeos.h
+++ b/device/bluetooth/bluetooth_device_chromeos.h
@@ -88,6 +88,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceChromeOS
// Returns the object path of the device.
const dbus::ObjectPath& object_path() const { return object_path_; }
+ // Returns the adapter which owns this device instance.
+ BluetoothAdapterChromeOS* adapter() const { return adapter_; }
+
protected:
// BluetoothDevice override
std::string GetDeviceName() const override;
diff --git a/device/bluetooth/bluetooth_socket_chromeos.cc b/device/bluetooth/bluetooth_socket_chromeos.cc
index e401a3d..192094f 100644
--- a/device/bluetooth/bluetooth_socket_chromeos.cc
+++ b/device/bluetooth/bluetooth_socket_chromeos.cc
@@ -28,6 +28,7 @@
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
+#include "device/bluetooth/bluetooth_adapter_profile_chromeos.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_chromeos.h"
#include "device/bluetooth/bluetooth_socket.h"
@@ -76,12 +77,11 @@ BluetoothSocketChromeOS::ConnectionRequest::~ConnectionRequest() {}
BluetoothSocketChromeOS::BluetoothSocketChromeOS(
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
scoped_refptr<BluetoothSocketThread> socket_thread)
- : BluetoothSocketNet(ui_task_runner, socket_thread) {
+ : BluetoothSocketNet(ui_task_runner, socket_thread), profile_(nullptr) {
}
BluetoothSocketChromeOS::~BluetoothSocketChromeOS() {
- DCHECK(object_path_.value().empty());
- DCHECK(profile_.get() == NULL);
+ DCHECK(!profile_);
if (adapter_.get()) {
adapter_->RemoveObserver(this);
@@ -96,8 +96,7 @@ void BluetoothSocketChromeOS::Connect(
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- DCHECK(object_path_.value().empty());
- DCHECK(!profile_.get());
+ DCHECK(!profile_);
if (!uuid.IsValid()) {
error_callback.Run(kInvalidUUID);
@@ -111,7 +110,7 @@ void BluetoothSocketChromeOS::Connect(
if (security_level == SECURITY_LEVEL_LOW)
options_->require_authentication.reset(new bool(false));
- RegisterProfile(success_callback, error_callback);
+ RegisterProfile(device->adapter(), success_callback, error_callback);
}
void BluetoothSocketChromeOS::Listen(
@@ -122,8 +121,7 @@ void BluetoothSocketChromeOS::Listen(
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- DCHECK(object_path_.value().empty());
- DCHECK(!profile_.get());
+ DCHECK(!profile_);
if (!uuid.IsValid()) {
error_callback.Run(kInvalidUUID);
@@ -151,7 +149,8 @@ void BluetoothSocketChromeOS::Listen(
NOTREACHED();
}
- RegisterProfile(success_callback, error_callback);
+ RegisterProfile(static_cast<BluetoothAdapterChromeOS*>(adapter_.get()),
+ success_callback, error_callback);
}
void BluetoothSocketChromeOS::Close() {
@@ -216,96 +215,76 @@ void BluetoothSocketChromeOS::Accept(
}
void BluetoothSocketChromeOS::RegisterProfile(
+ BluetoothAdapterChromeOS* adapter,
const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- DCHECK(object_path_.value().empty());
- DCHECK(!profile_.get());
-
- // The object path is relatively meaningless, but has to be unique, so for
- // connecting profiles use a combination of the device address and profile
- // UUID.
- std::string device_address_path, uuid_path;
- base::ReplaceChars(device_address_, ":-", "_", &device_address_path);
- base::ReplaceChars(uuid_.canonical_value(), ":-", "_", &uuid_path);
- if (!device_address_path.empty()) {
- object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
- device_address_path + "/" + uuid_path);
- } else {
- object_path_ = dbus::ObjectPath("/org/chromium/bluetooth_profile/" +
- uuid_path);
- }
-
- // Create the service provider for the profile object.
- dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus();
- profile_.reset(BluetoothProfileServiceProvider::Create(
- system_bus, object_path_, this));
- DCHECK(profile_.get());
+ DCHECK(!profile_);
+ DCHECK(adapter);
- // Before reaching out to the Bluetooth Daemon to register a listening socket,
- // make sure it's actually running. If not, report success and carry on;
+ // If the adapter is not present, this is a listening socket and the
+ // adapter isn't running yet. Report success and carry on;
// the profile will be registered when the daemon becomes available.
- if (adapter_.get() && !adapter_->IsPresent()) {
- VLOG(1) << object_path_.value() << ": Delaying profile registration.";
- success_callback.Run();
+ if (!adapter->IsPresent()) {
+ VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
+ << ": Delaying profile registration.";
+ base::MessageLoop::current()->PostTask(FROM_HERE, success_callback);
return;
}
- VLOG(1) << object_path_.value() << ": Registering profile.";
- DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
- RegisterProfile(
- object_path_,
- uuid_.canonical_value(),
- *options_,
- base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile,
- this,
- success_callback,
- error_callback),
- base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError,
- this,
- error_callback));
+ VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
+ << ": Acquiring profile.";
+
+ adapter->UseProfile(
+ uuid_, device_path_, *options_, this,
+ base::Bind(&BluetoothSocketChromeOS::OnRegisterProfile, this,
+ success_callback, error_callback),
+ base::Bind(&BluetoothSocketChromeOS::OnRegisterProfileError, this,
+ error_callback));
}
void BluetoothSocketChromeOS::OnRegisterProfile(
const base::Closure& success_callback,
- const ErrorCompletionCallback& error_callback) {
+ const ErrorCompletionCallback& error_callback,
+ BluetoothAdapterProfileChromeOS* profile) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- if (!device_path_.value().empty()) {
- VLOG(1) << object_path_.value() << ": Profile registered, connecting to "
- << device_path_.value();
+ DCHECK(!profile_);
- DBusThreadManager::Get()->GetBluetoothDeviceClient()->
- ConnectProfile(
- device_path_,
- uuid_.canonical_value(),
- base::Bind(
- &BluetoothSocketChromeOS::OnConnectProfile,
- this,
- success_callback),
- base::Bind(
- &BluetoothSocketChromeOS::OnConnectProfileError,
- this,
- error_callback));
- } else {
- VLOG(1) << object_path_.value() << ": Profile registered.";
+ profile_ = profile;
+
+ if (device_path_.value().empty()) {
+ VLOG(1) << uuid_.canonical_value() << ": Profile registered.";
success_callback.Run();
+ return;
}
+
+ VLOG(1) << uuid_.canonical_value() << ": Got profile, connecting to "
+ << device_path_.value();
+
+ DBusThreadManager::Get()->GetBluetoothDeviceClient()->ConnectProfile(
+ device_path_, uuid_.canonical_value(),
+ base::Bind(&BluetoothSocketChromeOS::OnConnectProfile, this,
+ success_callback),
+ base::Bind(&BluetoothSocketChromeOS::OnConnectProfileError, this,
+ error_callback));
}
void BluetoothSocketChromeOS::OnRegisterProfileError(
const ErrorCompletionCallback& error_callback,
- const std::string& error_name,
const std::string& error_message) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- LOG(WARNING) << object_path_.value() << ": Failed to register profile: "
- << error_name << ": " << error_message;
+
+ LOG(WARNING) << uuid_.canonical_value()
+ << ": Failed to register profile: " << error_message;
error_callback.Run(error_message);
}
void BluetoothSocketChromeOS::OnConnectProfile(
const base::Closure& success_callback) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- VLOG(1) << object_path_.value() << ": Profile connected.";
+ DCHECK(profile_);
+
+ VLOG(1) << profile_->object_path().value() << ": Profile connected.";
UnregisterProfile();
success_callback.Run();
}
@@ -315,8 +294,11 @@ void BluetoothSocketChromeOS::OnConnectProfileError(
const std::string& error_name,
const std::string& error_message) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- LOG(WARNING) << object_path_.value() << ": Failed to connect profile: "
- << error_name << ": " << error_message;
+ DCHECK(profile_);
+
+ LOG(WARNING) << profile_->object_path().value()
+ << ": Failed to connect profile: " << error_name << ": "
+ << error_message;
UnregisterProfile();
error_callback.Run(error_message);
}
@@ -324,47 +306,47 @@ void BluetoothSocketChromeOS::OnConnectProfileError(
void BluetoothSocketChromeOS::AdapterPresentChanged(BluetoothAdapter* adapter,
bool present) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- DCHECK(!object_path_.value().empty());
- DCHECK(profile_.get());
- if (!present)
+ if (!present) {
+ // Adapter removed, the profile is now invalid.
+ UnregisterProfile();
return;
+ }
+
+ DCHECK(!profile_);
- VLOG(1) << object_path_.value() << ": Re-register profile.";
- DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
- RegisterProfile(
- object_path_,
- uuid_.canonical_value(),
- *options_,
- base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile,
- this),
- base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError,
- this));
+ VLOG(1) << uuid_.canonical_value() << " on " << device_path_.value()
+ << ": Acquiring profile.";
+
+ static_cast<BluetoothAdapterChromeOS*>(adapter)->UseProfile(
+ uuid_, device_path_, *options_, this,
+ base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfile, this),
+ base::Bind(&BluetoothSocketChromeOS::OnInternalRegisterProfileError,
+ this));
}
-void BluetoothSocketChromeOS::OnInternalRegisterProfile() {
+void BluetoothSocketChromeOS::OnInternalRegisterProfile(
+ BluetoothAdapterProfileChromeOS* profile) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
+ DCHECK(!profile_);
+
+ profile_ = profile;
- VLOG(1) << object_path_.value() << ": Profile re-registered";
+ VLOG(1) << uuid_.canonical_value() << ": Profile re-registered";
}
void BluetoothSocketChromeOS::OnInternalRegisterProfileError(
- const std::string& error_name,
const std::string& error_message) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- // It's okay if the profile already exists, it means we registered it on
- // initialization.
- if (error_name == bluetooth_profile_manager::kErrorAlreadyExists)
- return;
-
- LOG(WARNING) << object_path_.value() << ": Failed to re-register profile: "
- << error_name << ": " << error_message;
+ LOG(WARNING) << "Failed to re-register profile: " << error_message;
}
void BluetoothSocketChromeOS::Released() {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- VLOG(1) << object_path_.value() << ": Release";
+ DCHECK(profile_);
+
+ VLOG(1) << profile_->object_path().value() << ": Release";
}
void BluetoothSocketChromeOS::NewConnection(
@@ -373,8 +355,9 @@ void BluetoothSocketChromeOS::NewConnection(
const BluetoothProfileServiceProvider::Delegate::Options& options,
const ConfirmationCallback& callback) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- VLOG(1) << object_path_.value() << ": New connection from device: "
- << device_path.value();
+
+ VLOG(1) << uuid_.canonical_value()
+ << ": New connection from device: " << device_path.value();
if (!device_path_.value().empty()) {
DCHECK(device_path_ == device_path);
@@ -396,7 +379,7 @@ void BluetoothSocketChromeOS::NewConnection(
request->callback = callback;
connection_request_queue_.push(request);
- VLOG(1) << object_path_.value() << ": Connection is now pending.";
+ VLOG(1) << uuid_.canonical_value() << ": Connection is now pending.";
if (accept_request_) {
AcceptConnectionRequest();
}
@@ -407,13 +390,17 @@ void BluetoothSocketChromeOS::RequestDisconnection(
const dbus::ObjectPath& device_path,
const ConfirmationCallback& callback) {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- VLOG(1) << object_path_.value() << ": Request disconnection";
+ DCHECK(profile_);
+
+ VLOG(1) << profile_->object_path().value() << ": Request disconnection";
callback.Run(SUCCESS);
}
void BluetoothSocketChromeOS::Cancel() {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- VLOG(1) << object_path_.value() << ": Cancel";
+ DCHECK(profile_);
+
+ VLOG(1) << profile_->object_path().value() << ": Cancel";
if (!connection_request_queue_.size())
return;
@@ -432,8 +419,10 @@ void BluetoothSocketChromeOS::AcceptConnectionRequest() {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
DCHECK(accept_request_.get());
DCHECK(connection_request_queue_.size() >= 1);
+ DCHECK(profile_);
- VLOG(1) << object_path_.value() << ": Accepting pending connection.";
+ VLOG(1) << profile_->object_path().value()
+ << ": Accepting pending connection.";
linked_ptr<ConnectionRequest> request = connection_request_queue_.front();
request->accepting = true;
@@ -474,9 +463,9 @@ void BluetoothSocketChromeOS::DoNewConnection(
base::ThreadRestrictions::AssertIOAllowed();
fd->CheckValidity();
- VLOG(1) << object_path_.value() << ": Validity check complete.";
+ VLOG(1) << uuid_.canonical_value() << ": Validity check complete.";
if (!fd->is_valid()) {
- LOG(WARNING) << object_path_.value() << " :" << fd->value()
+ LOG(WARNING) << uuid_.canonical_value() << " :" << fd->value()
<< ": Invalid file descriptor received from Bluetooth Daemon.";
ui_task_runner()->PostTask(FROM_HERE,
base::Bind(callback, REJECTED));;
@@ -484,7 +473,7 @@ void BluetoothSocketChromeOS::DoNewConnection(
}
if (tcp_socket()) {
- LOG(WARNING) << object_path_.value() << ": Already connected";
+ LOG(WARNING) << uuid_.canonical_value() << ": Already connected";
ui_task_runner()->PostTask(FROM_HERE,
base::Bind(callback, REJECTED));;
return;
@@ -497,14 +486,15 @@ void BluetoothSocketChromeOS::DoNewConnection(
int net_result = tcp_socket()->AdoptConnectedSocket(fd->value(),
net::IPEndPoint());
if (net_result != net::OK) {
- LOG(WARNING) << object_path_.value() << ": Error adopting socket: "
+ LOG(WARNING) << uuid_.canonical_value() << ": Error adopting socket: "
<< std::string(net::ErrorToString(net_result));
ui_task_runner()->PostTask(FROM_HERE,
base::Bind(callback, REJECTED));;
return;
}
- VLOG(2) << object_path_.value() << ": Taking descriptor, confirming success.";
+ VLOG(2) << uuid_.canonical_value()
+ << ": Taking descriptor, confirming success.";
fd->TakeValue();
ui_task_runner()->PostTask(FROM_HERE,
base::Bind(callback, SUCCESS));;
@@ -554,40 +544,20 @@ void BluetoothSocketChromeOS::DoCloseListening() {
void BluetoothSocketChromeOS::UnregisterProfile() {
DCHECK(ui_task_runner()->RunsTasksOnCurrentThread());
- DCHECK(!object_path_.value().empty());
- DCHECK(profile_.get());
-
- VLOG(1) << object_path_.value() << ": Unregister profile";
- DBusThreadManager::Get()->GetBluetoothProfileManagerClient()->
- UnregisterProfile(
- object_path_,
- base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfile,
- this,
- object_path_),
- base::Bind(&BluetoothSocketChromeOS::OnUnregisterProfileError,
- this,
- object_path_));
+ DCHECK(profile_);
- profile_.reset();
- object_path_ = dbus::ObjectPath("");
-}
+ VLOG(1) << profile_->object_path().value() << ": Release profile";
-void BluetoothSocketChromeOS::OnUnregisterProfile(
- const dbus::ObjectPath& object_path) {
- VLOG(1) << object_path.value() << ": Profile unregistered";
-}
+ profile_->RemoveDelegate(
+ device_path_, base::Bind(&BluetoothSocketChromeOS::ReleaseProfile, this));
-void BluetoothSocketChromeOS::OnUnregisterProfileError(
- const dbus::ObjectPath& object_path,
- const std::string& error_name,
- const std::string& error_message) {
- // It's okay if the profile doesn't exist, it means we haven't registered it
- // yet.
- if (error_name == bluetooth_profile_manager::kErrorDoesNotExist)
- return;
+ profile_ = nullptr;
+}
- LOG(WARNING) << object_path_.value() << ": Failed to unregister profile: "
- << error_name << ": " << error_message;
+void BluetoothSocketChromeOS::ReleaseProfile() {
+ if (adapter_)
+ static_cast<BluetoothAdapterChromeOS*>(adapter_.get())
+ ->ReleaseProfile(uuid_);
}
} // namespace chromeos
diff --git a/device/bluetooth/bluetooth_socket_chromeos.h b/device/bluetooth/bluetooth_socket_chromeos.h
index 640292e..d4a56b5 100644
--- a/device/bluetooth/bluetooth_socket_chromeos.h
+++ b/device/bluetooth/bluetooth_socket_chromeos.h
@@ -26,6 +26,8 @@ class FileDescriptor;
namespace chromeos {
class BluetoothDeviceChromeOS;
+class BluetoothAdapterChromeOS;
+class BluetoothAdapterProfileChromeOS;
// The BluetoothSocketChromeOS class implements BluetoothSocket for the
// Chrome OS platform.
@@ -75,9 +77,6 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
void Accept(const AcceptCompletionCallback& success_callback,
const ErrorCompletionCallback& error_callback) override;
- // Returns the object path of the socket.
- const dbus::ObjectPath& object_path() const { return object_path_; }
-
protected:
~BluetoothSocketChromeOS() override;
@@ -87,12 +86,13 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
scoped_refptr<device::BluetoothSocketThread> socket_thread);
// Register the underlying profile client object with the Bluetooth Daemon.
- void RegisterProfile(const base::Closure& success_callback,
+ void RegisterProfile(BluetoothAdapterChromeOS* adapter,
+ const base::Closure& success_callback,
const ErrorCompletionCallback& error_callback);
void OnRegisterProfile(const base::Closure& success_callback,
- const ErrorCompletionCallback& error_callback);
+ const ErrorCompletionCallback& error_callback,
+ BluetoothAdapterProfileChromeOS* profile);
void OnRegisterProfileError(const ErrorCompletionCallback& error_callback,
- const std::string& error_name,
const std::string& error_message);
// Called by dbus:: on completion of the ConnectProfile() method.
@@ -107,9 +107,8 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
// Called by dbus:: on completion of the RegisterProfile() method call
// triggered as a result of the adapter becoming present again.
- void OnInternalRegisterProfile();
- void OnInternalRegisterProfileError(const std::string& error_name,
- const std::string& error_message);
+ void OnInternalRegisterProfile(BluetoothAdapterProfileChromeOS* profile);
+ void OnInternalRegisterProfileError(const std::string& error_message);
// BluetoothProfileServiceProvider::Delegate:
void Released() override;
@@ -151,13 +150,11 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
// Unregister the underlying profile client object from the Bluetooth Daemon.
void UnregisterProfile();
- void OnUnregisterProfile(const dbus::ObjectPath& object_path);
- void OnUnregisterProfileError(const dbus::ObjectPath& object_path,
- const std::string& error_name,
- const std::string& error_message);
- // Adapter the profile is registered against; this is only present when the
- // socket is listening.
+ // Releases the profile after the delegate is gone.
+ void ReleaseProfile();
+
+ // Adapter the profile is registered against
scoped_refptr<device::BluetoothAdapter> adapter_;
// Address and D-Bus object path of the device being connected to, empty and
@@ -171,12 +168,8 @@ class CHROMEOS_EXPORT BluetoothSocketChromeOS
// Copy of the profile options used for registering the profile.
scoped_ptr<BluetoothProfileManagerClient::Options> options_;
- // Object path of the local profile D-Bus object.
- dbus::ObjectPath object_path_;
-
- // Local profile D-Bus object used for receiving profile delegate methods
- // from BlueZ.
- scoped_ptr<BluetoothProfileServiceProvider> profile_;
+ // The profile registered with the adapter for this socket.
+ BluetoothAdapterProfileChromeOS* profile_;
// Pending request to an Accept() call.
struct AcceptRequest {
diff --git a/device/bluetooth/bluetooth_socket_chromeos_unittest.cc b/device/bluetooth/bluetooth_socket_chromeos_unittest.cc
index 1a4aa96..79d43ae 100644
--- a/device/bluetooth/bluetooth_socket_chromeos_unittest.cc
+++ b/device/bluetooth/bluetooth_socket_chromeos_unittest.cc
@@ -12,6 +12,7 @@
#include "chromeos/dbus/fake_bluetooth_gatt_service_client.h"
#include "chromeos/dbus/fake_bluetooth_input_client.h"
#include "chromeos/dbus/fake_bluetooth_profile_manager_client.h"
+#include "chromeos/dbus/fake_bluetooth_profile_service_provider.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_chromeos.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -144,6 +145,9 @@ class BluetoothSocketChromeOSTest : public testing::Test {
void CreateServiceSuccessCallback(scoped_refptr<BluetoothSocket> socket) {
++success_callback_count_;
last_socket_ = socket;
+
+ if (message_loop_.is_running())
+ message_loop_.Quit();
}
void AcceptSuccessCallback(const BluetoothDevice* device,
@@ -187,7 +191,6 @@ TEST_F(BluetoothSocketChromeOSTest, Connect) {
base::Unretained(this)),
base::Bind(&BluetoothSocketChromeOSTest::ErrorCallback,
base::Unretained(this)));
-
message_loop_.Run();
EXPECT_EQ(1U, success_callback_count_);
@@ -297,6 +300,8 @@ TEST_F(BluetoothSocketChromeOSTest, Listen) {
base::Bind(&BluetoothSocketChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.Run();
+
EXPECT_EQ(1U, success_callback_count_);
EXPECT_EQ(0U, error_callback_count_);
EXPECT_TRUE(last_socket_.get() != NULL);
@@ -325,6 +330,8 @@ TEST_F(BluetoothSocketChromeOSTest, Listen) {
base::Bind(&base::DoNothing),
base::Bind(&DoNothingDBusErrorCallback));
+ message_loop_.RunUntilIdle();
+
server_socket->Accept(
base::Bind(&BluetoothSocketChromeOSTest::AcceptSuccessCallback,
base::Unretained(this)),
@@ -363,6 +370,8 @@ TEST_F(BluetoothSocketChromeOSTest, Listen) {
base::Bind(&BluetoothSocketChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.RunUntilIdle();
+
fake_bluetooth_device_client->ConnectProfile(
static_cast<BluetoothDeviceChromeOS*>(device)->object_path(),
FakeBluetoothProfileManagerClient::kRfcommUuid,
@@ -398,6 +407,8 @@ TEST_F(BluetoothSocketChromeOSTest, Listen) {
base::Bind(&BluetoothSocketChromeOSTest::ImmediateSuccessCallback,
base::Unretained(this)));
+ message_loop_.RunUntilIdle();
+
EXPECT_EQ(1U, success_callback_count_);
}
@@ -416,6 +427,7 @@ TEST_F(BluetoothSocketChromeOSTest, ListenBeforeAdapterStart) {
base::Unretained(this)),
base::Bind(&BluetoothSocketChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.Run();
EXPECT_EQ(1U, success_callback_count_);
EXPECT_EQ(0U, error_callback_count_);
@@ -439,6 +451,8 @@ TEST_F(BluetoothSocketChromeOSTest, ListenBeforeAdapterStart) {
// Make the adapter visible. This should register a profile.
fake_bluetooth_adapter_client->SetVisible(true);
+ message_loop_.RunUntilIdle();
+
profile_service_provider =
fake_bluetooth_profile_manager_client->GetProfileServiceProvider(
FakeBluetoothProfileManagerClient::kRfcommUuid);
@@ -449,6 +463,8 @@ TEST_F(BluetoothSocketChromeOSTest, ListenBeforeAdapterStart) {
base::Bind(&BluetoothSocketChromeOSTest::ImmediateSuccessCallback,
base::Unretained(this)));
+ message_loop_.RunUntilIdle();
+
EXPECT_EQ(1U, success_callback_count_);
}
@@ -465,6 +481,7 @@ TEST_F(BluetoothSocketChromeOSTest, ListenAcrossAdapterRestart) {
base::Unretained(this)),
base::Bind(&BluetoothSocketChromeOSTest::ErrorCallback,
base::Unretained(this)));
+ message_loop_.Run();
EXPECT_EQ(1U, success_callback_count_);
EXPECT_EQ(0U, error_callback_count_);
@@ -488,14 +505,14 @@ TEST_F(BluetoothSocketChromeOSTest, ListenAcrossAdapterRestart) {
// Make the adapter invisible, and fiddle with the profile fake to unregister
// the profile since this doesn't happen automatically.
fake_bluetooth_adapter_client->SetVisible(false);
- fake_bluetooth_profile_manager_client->UnregisterProfile(
- static_cast<BluetoothSocketChromeOS*>(socket.get())->object_path(),
- base::Bind(&base::DoNothing),
- base::Bind(&DoNothingDBusErrorCallback));
+
+ message_loop_.RunUntilIdle();
// Then make the adapter visible again. This should re-register the profile.
fake_bluetooth_adapter_client->SetVisible(true);
+ message_loop_.RunUntilIdle();
+
profile_service_provider =
fake_bluetooth_profile_manager_client->GetProfileServiceProvider(
FakeBluetoothProfileManagerClient::kRfcommUuid);
@@ -506,6 +523,8 @@ TEST_F(BluetoothSocketChromeOSTest, ListenAcrossAdapterRestart) {
base::Bind(&BluetoothSocketChromeOSTest::ImmediateSuccessCallback,
base::Unretained(this)));
+ message_loop_.RunUntilIdle();
+
EXPECT_EQ(1U, success_callback_count_);
}
diff --git a/device/device_tests.gyp b/device/device_tests.gyp
index df4f264..a38cd2c 100644
--- a/device/device_tests.gyp
+++ b/device/device_tests.gyp
@@ -34,6 +34,7 @@
'battery/battery_status_service_unittest.cc',
'bluetooth/bluetooth_adapter_mac_unittest.mm',
'bluetooth/bluetooth_adapter_unittest.cc',
+ 'bluetooth/bluetooth_adapter_profile_chromeos_unittest.cc',
'bluetooth/bluetooth_adapter_win_unittest.cc',
'bluetooth/bluetooth_device_unittest.cc',
'bluetooth/bluetooth_device_win_unittest.cc',