diff options
-rw-r--r-- | chromeos/dbus/fake_bluetooth_agent_manager_client.cc | 7 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.cc | 336 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.h | 120 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_device_chromeos.cc | 328 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_device_chromeos.h | 63 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_profile_chromeos_unittest.cc | 4 |
6 files changed, 501 insertions, 357 deletions
diff --git a/chromeos/dbus/fake_bluetooth_agent_manager_client.cc b/chromeos/dbus/fake_bluetooth_agent_manager_client.cc index 2672ad5..b2bdf96 100644 --- a/chromeos/dbus/fake_bluetooth_agent_manager_client.cc +++ b/chromeos/dbus/fake_bluetooth_agent_manager_client.cc @@ -45,8 +45,11 @@ void FakeBluetoothAgentManagerClient::UnregisterAgent( const base::Closure& callback, const ErrorCallback& error_callback) { VLOG(1) << "UnregisterAgent: " << agent_path.value(); - if (service_provider_ != NULL) { - error_callback.Run(bluetooth_agent_manager::kErrorInvalidArguments, + if (service_provider_ == NULL) { + error_callback.Run(bluetooth_agent_manager::kErrorDoesNotExist, + "No agent registered"); + } else if (service_provider_->object_path_ != agent_path) { + error_callback.Run(bluetooth_agent_manager::kErrorDoesNotExist, "Agent still registered"); } else { callback.Run(); diff --git a/device/bluetooth/bluetooth_adapter_chromeos.cc b/device/bluetooth/bluetooth_adapter_chromeos.cc index 0d962b9..3344392 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.cc +++ b/device/bluetooth/bluetooth_adapter_chromeos.cc @@ -11,15 +11,45 @@ #include "base/metrics/histogram.h" #include "base/sys_info.h" #include "chromeos/dbus/bluetooth_adapter_client.h" +#include "chromeos/dbus/bluetooth_agent_manager_client.h" +#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/dbus_thread_manager.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_device_chromeos.h" +#include "third_party/cros_system_api/dbus/service_constants.h" using device::BluetoothAdapter; using device::BluetoothDevice; +namespace { + +// The agent path is relatively meaningless since BlueZ only permits one to +// exist per D-Bus connection, it just has to be unique within Chromium. +const char kAgentPath[] = "/org/chromium/bluetooth_agent"; + +// Histogram enumerations for pairing methods. +enum UMAPairingMethod { + UMA_PAIRING_METHOD_NONE, + UMA_PAIRING_METHOD_REQUEST_PINCODE, + UMA_PAIRING_METHOD_REQUEST_PASSKEY, + UMA_PAIRING_METHOD_DISPLAY_PINCODE, + UMA_PAIRING_METHOD_DISPLAY_PASSKEY, + UMA_PAIRING_METHOD_CONFIRM_PASSKEY, + // NOTE: Add new pairing methods immediately above this line. Make sure to + // update the enum list in tools/histogram/histograms.xml accordingly. + UMA_PAIRING_METHOD_COUNT +}; + +void OnUnregisterAgentError(const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << "Failed to unregister pairing agent: " + << error_name << ": " << error_message; +} + +} // namespace + namespace chromeos { BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() @@ -35,12 +65,35 @@ BluetoothAdapterChromeOS::BluetoothAdapterChromeOS() VLOG(1) << object_paths.size() << " Bluetooth adapter(s) available."; SetAdapter(object_paths[0]); } + + // Register the pairing agent. + dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); + agent_.reset(BluetoothAgentServiceProvider::Create( + system_bus, dbus::ObjectPath(kAgentPath), this)); + DCHECK(agent_.get()); + + VLOG(1) << "Registering pairing agent"; + DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> + RegisterAgent( + dbus::ObjectPath(kAgentPath), + bluetooth_agent_manager::kKeyboardDisplayCapability, + base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgent, + weak_ptr_factory_.GetWeakPtr()), + base::Bind(&BluetoothAdapterChromeOS::OnRegisterAgentError, + weak_ptr_factory_.GetWeakPtr())); } BluetoothAdapterChromeOS::~BluetoothAdapterChromeOS() { DBusThreadManager::Get()->GetBluetoothAdapterClient()->RemoveObserver(this); DBusThreadManager::Get()->GetBluetoothDeviceClient()->RemoveObserver(this); DBusThreadManager::Get()->GetBluetoothInputClient()->RemoveObserver(this); + + VLOG(1) << "Unregistering pairing agent"; + DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> + UnregisterAgent( + dbus::ObjectPath(kAgentPath), + base::Bind(&base::DoNothing), + base::Bind(&OnUnregisterAgentError)); } void BluetoothAdapterChromeOS::AddObserver( @@ -315,6 +368,267 @@ void BluetoothAdapterChromeOS::InputPropertyChanged( NotifyDeviceChanged(device_chromeos); } +void BluetoothAdapterChromeOS::Release() { + DCHECK(agent_.get()); + VLOG(1) << "Release"; + + // Called after we unregister the pairing agent, e.g. when changing I/O + // capabilities. Nothing much to be done right now. +} + +void BluetoothAdapterChromeOS::RequestPinCode( + const dbus::ObjectPath& device_path, + const PinCodeCallback& callback) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": RequestPinCode"; + + BluetoothDeviceChromeOS* device_chromeos; + PairingContext* pairing_context; + if (!GetDeviceAndPairingContext(device_path, + &device_chromeos, &pairing_context)) { + callback.Run(REJECTED, ""); + return; + } + + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", + UMA_PAIRING_METHOD_REQUEST_PINCODE, + UMA_PAIRING_METHOD_COUNT); + + DCHECK(pairing_context->pincode_callback_.is_null()); + pairing_context->pincode_callback_ = callback; + pairing_context->pairing_delegate_->RequestPinCode(device_chromeos); + pairing_context->pairing_delegate_used_ = true; +} + +void BluetoothAdapterChromeOS::DisplayPinCode( + const dbus::ObjectPath& device_path, + const std::string& pincode) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": DisplayPinCode: " << pincode; + + BluetoothDeviceChromeOS* device_chromeos; + PairingContext* pairing_context; + if (!GetDeviceAndPairingContext(device_path, + &device_chromeos, &pairing_context)) + return; + + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", + UMA_PAIRING_METHOD_DISPLAY_PINCODE, + UMA_PAIRING_METHOD_COUNT); + + pairing_context->pairing_delegate_->DisplayPinCode(device_chromeos, pincode); + pairing_context->pairing_delegate_used_ = true; +} + +void BluetoothAdapterChromeOS::RequestPasskey( + const dbus::ObjectPath& device_path, + const PasskeyCallback& callback) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": RequestPasskey"; + + BluetoothDeviceChromeOS* device_chromeos; + PairingContext* pairing_context; + if (!GetDeviceAndPairingContext(device_path, + &device_chromeos, &pairing_context)) { + callback.Run(REJECTED, 0); + return; + } + + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", + UMA_PAIRING_METHOD_REQUEST_PASSKEY, + UMA_PAIRING_METHOD_COUNT); + + DCHECK(pairing_context->passkey_callback_.is_null()); + pairing_context->passkey_callback_ = callback; + pairing_context->pairing_delegate_->RequestPasskey(device_chromeos); + pairing_context->pairing_delegate_used_ = true; +} + +void BluetoothAdapterChromeOS::DisplayPasskey( + const dbus::ObjectPath& device_path, + uint32 passkey, + uint16 entered) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": DisplayPasskey: " << passkey + << " (" << entered << " entered)"; + + BluetoothDeviceChromeOS* device_chromeos; + PairingContext* pairing_context; + if (!GetDeviceAndPairingContext(device_path, + &device_chromeos, &pairing_context)) + return; + + if (entered == 0) + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", + UMA_PAIRING_METHOD_DISPLAY_PASSKEY, + UMA_PAIRING_METHOD_COUNT); + + if (entered == 0) + pairing_context->pairing_delegate_->DisplayPasskey(device_chromeos, + passkey); + + pairing_context->pairing_delegate_->KeysEntered(device_chromeos, entered); + pairing_context->pairing_delegate_used_ = true; +} + +void BluetoothAdapterChromeOS::RequestConfirmation( + const dbus::ObjectPath& device_path, + uint32 passkey, + const ConfirmationCallback& callback) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": RequestConfirmation: " << passkey; + + BluetoothDeviceChromeOS* device_chromeos; + PairingContext* pairing_context; + if (!GetDeviceAndPairingContext(device_path, + &device_chromeos, &pairing_context)) { + callback.Run(REJECTED); + return; + } + + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", + UMA_PAIRING_METHOD_CONFIRM_PASSKEY, + UMA_PAIRING_METHOD_COUNT); + + DCHECK(pairing_context->confirmation_callback_.is_null()); + pairing_context->confirmation_callback_ = callback; + pairing_context->pairing_delegate_->ConfirmPasskey(device_chromeos, passkey); + pairing_context->pairing_delegate_used_ = true; +} + +void BluetoothAdapterChromeOS::RequestAuthorization( + const dbus::ObjectPath& device_path, + const ConfirmationCallback& callback) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": RequestAuthorization"; + + // TODO(keybuk): implement + callback.Run(CANCELLED); +} + +void BluetoothAdapterChromeOS::AuthorizeService( + const dbus::ObjectPath& device_path, + const std::string& uuid, + const ConfirmationCallback& callback) { + DCHECK(agent_.get()); + VLOG(1) << device_path.value() << ": AuthorizeService: " << uuid; + + // TODO(keybuk): implement + callback.Run(CANCELLED); +} + +void BluetoothAdapterChromeOS::Cancel() { + DCHECK(agent_.get()); + VLOG(1) << "Cancel"; +} + +bool BluetoothAdapterChromeOS::PairingContext::ExpectingPinCode() const { + return !pincode_callback_.is_null(); +} + +bool BluetoothAdapterChromeOS::PairingContext::ExpectingPasskey() const { + return !passkey_callback_.is_null(); +} + +bool BluetoothAdapterChromeOS::PairingContext::ExpectingConfirmation() const { + return !confirmation_callback_.is_null(); +} + +void BluetoothAdapterChromeOS::PairingContext::SetPinCode( + const std::string& pincode) { + if (pincode_callback_.is_null()) + return; + + pincode_callback_.Run(SUCCESS, pincode); + pincode_callback_.Reset(); +} + +void BluetoothAdapterChromeOS::PairingContext::SetPasskey(uint32 passkey) { + if (passkey_callback_.is_null()) + return; + + passkey_callback_.Run(SUCCESS, passkey); + passkey_callback_.Reset(); +} + +void BluetoothAdapterChromeOS::PairingContext::ConfirmPairing() { + if (confirmation_callback_.is_null()) + return; + + confirmation_callback_.Run(SUCCESS); + confirmation_callback_.Reset(); +} + +bool BluetoothAdapterChromeOS::PairingContext::RejectPairing() { + return RunPairingCallbacks(REJECTED); +} + +bool BluetoothAdapterChromeOS::PairingContext::CancelPairing() { + return RunPairingCallbacks(CANCELLED); +} + +BluetoothAdapterChromeOS::PairingContext::PairingContext( + BluetoothDevice::PairingDelegate* pairing_delegate) + : pairing_delegate_(pairing_delegate), + pairing_delegate_used_(false) { + VLOG(1) << "Created PairingContext"; +} + +BluetoothAdapterChromeOS::PairingContext::~PairingContext() { + VLOG(1) << "Destroying PairingContext"; + + if (!pairing_delegate_used_) + UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", + UMA_PAIRING_METHOD_NONE, + UMA_PAIRING_METHOD_COUNT); + + DCHECK(pincode_callback_.is_null()); + DCHECK(passkey_callback_.is_null()); + DCHECK(confirmation_callback_.is_null()); + + pairing_delegate_->DismissDisplayOrConfirm(); + pairing_delegate_ = NULL; +} + +bool BluetoothAdapterChromeOS::PairingContext::RunPairingCallbacks( + BluetoothAgentServiceProvider::Delegate::Status status) { + pairing_delegate_used_ = true; + + bool callback_run = false; + if (!pincode_callback_.is_null()) { + pincode_callback_.Run(status, ""); + pincode_callback_.Reset(); + callback_run = true; + } + + if (!passkey_callback_.is_null()) { + passkey_callback_.Run(status, 0); + passkey_callback_.Reset(); + callback_run = true; + } + + if (!confirmation_callback_.is_null()) { + confirmation_callback_.Run(status); + confirmation_callback_.Reset(); + callback_run = true; + } + + return callback_run; +} + +void BluetoothAdapterChromeOS::OnRegisterAgent() { + VLOG(1) << "Pairing agent registered"; +} + +void BluetoothAdapterChromeOS::OnRegisterAgentError( + const std::string& error_name, + const std::string& error_message) { + LOG(WARNING) << ": Failed to register pairing agent: " + << error_name << ": " << error_message; + + agent_.reset(); +} + BluetoothDeviceChromeOS* BluetoothAdapterChromeOS::GetDeviceWithPath( const dbus::ObjectPath& object_path) { @@ -329,6 +643,28 @@ BluetoothAdapterChromeOS::GetDeviceWithPath( return NULL; } +bool BluetoothAdapterChromeOS::GetDeviceAndPairingContext( + const dbus::ObjectPath& object_path, + BluetoothDeviceChromeOS** device_chromeos, + PairingContext** pairing_context) +{ + *device_chromeos = GetDeviceWithPath(object_path); + if (!device_chromeos) { + LOG(WARNING) << "Pairing Agent request for unknown device: " + << object_path.value(); + return false; + } + + *pairing_context = (*device_chromeos)->pairing_context_.get(); + if (*pairing_context) + return true; + + // TODO(keybuk): this is the point we need a default pairing delegate, create + // a PairingContext with that passed in, set it as the context on the device + // and return true. + return false; +} + void BluetoothAdapterChromeOS::SetAdapter(const dbus::ObjectPath& object_path) { DCHECK(!IsPresent()); object_path_ = object_path; diff --git a/device/bluetooth/bluetooth_adapter_chromeos.h b/device/bluetooth/bluetooth_adapter_chromeos.h index b400ed3..926ba86 100644 --- a/device/bluetooth/bluetooth_adapter_chromeos.h +++ b/device/bluetooth/bluetooth_adapter_chromeos.h @@ -9,10 +9,12 @@ #include "base/memory/weak_ptr.h" #include "chromeos/dbus/bluetooth_adapter_client.h" +#include "chromeos/dbus/bluetooth_agent_service_provider.h" #include "chromeos/dbus/bluetooth_device_client.h" #include "chromeos/dbus/bluetooth_input_client.h" #include "dbus/object_path.h" #include "device/bluetooth/bluetooth_adapter.h" +#include "device/bluetooth/bluetooth_device.h" namespace device { @@ -31,7 +33,8 @@ class BluetoothAdapterChromeOS : public device::BluetoothAdapter, private chromeos::BluetoothAdapterClient::Observer, private chromeos::BluetoothDeviceClient::Observer, - private chromeos::BluetoothInputClient::Observer { + private chromeos::BluetoothInputClient::Observer, + private chromeos::BluetoothAgentServiceProvider::Delegate { public: // BluetoothAdapter override virtual void AddObserver( @@ -94,11 +97,122 @@ class BluetoothAdapterChromeOS virtual void InputPropertyChanged(const dbus::ObjectPath& object_path, const std::string& property_name) OVERRIDE; + // BluetoothAgentServiceProvider::Delegate override. + virtual void Release() OVERRIDE; + virtual void RequestPinCode(const dbus::ObjectPath& device_path, + const PinCodeCallback& callback) OVERRIDE; + virtual void DisplayPinCode(const dbus::ObjectPath& device_path, + const std::string& pincode) OVERRIDE; + virtual void RequestPasskey(const dbus::ObjectPath& device_path, + const PasskeyCallback& callback) OVERRIDE; + virtual void DisplayPasskey(const dbus::ObjectPath& device_path, + uint32 passkey, uint16 entered) OVERRIDE; + virtual void RequestConfirmation(const dbus::ObjectPath& device_path, + uint32 passkey, + const ConfirmationCallback& callback) + OVERRIDE; + virtual void RequestAuthorization(const dbus::ObjectPath& device_path, + const ConfirmationCallback& callback) + OVERRIDE; + virtual void AuthorizeService(const dbus::ObjectPath& device_path, + const std::string& uuid, + const ConfirmationCallback& callback) OVERRIDE; + virtual void Cancel() OVERRIDE; + + // PairingContext is an API between BluetoothAdapterChromeOS and + // BluetoothDeviceChromeOS for a single pairing attempt, wrapping the + // callbacks of the underlying BluetoothAgentServiceProvider object. + class PairingContext { + public: + ~PairingContext(); + + // Indicates whether the device is currently pairing and expecting a + // PIN Code to be returned. + bool ExpectingPinCode() const; + + // Indicates whether the device is currently pairing and expecting a + // Passkey to be returned. + bool ExpectingPasskey() const; + + // Indicates whether the device is currently pairing and expecting + // confirmation of a displayed passkey. + bool ExpectingConfirmation() const; + + // Sends the PIN code |pincode| to the remote device during pairing. + // + // PIN Codes are generally required for Bluetooth 2.0 and earlier devices + // for which there is no automatic pairing or special handling. + void SetPinCode(const std::string& pincode); + + // Sends the Passkey |passkey| to the remote device during pairing. + // + // Passkeys are generally required for Bluetooth 2.1 and later devices + // which cannot provide input or display on their own, and don't accept + // passkey-less pairing, and are a numeric in the range 0-999999. + void SetPasskey(uint32 passkey); + + // Confirms to the remote device during pairing that a passkey provided by + // the ConfirmPasskey() delegate call is displayed on both devices. + void ConfirmPairing(); + + // Rejects a pairing or connection request from a remote device, returns + // false if there was no way to reject the pairing. + bool RejectPairing(); + + // Cancels a pairing or connection attempt to a remote device, returns + // false if there was no way to cancel the pairing. + bool CancelPairing(); + + private: + friend class BluetoothAdapterChromeOS; + friend class BluetoothDeviceChromeOS; + + explicit PairingContext( + device::BluetoothDevice::PairingDelegate* pairing_delegate_); + + // Internal method to response to the relevant callback for a RejectPairing + // or CancelPairing call. + bool RunPairingCallbacks( + BluetoothAgentServiceProvider::Delegate::Status status); + + // UI Pairing Delegate to make method calls on, this must live as long as + // the object capturing the PairingContext. + device::BluetoothDevice::PairingDelegate* pairing_delegate_; + + // Flag to indicate whether any pairing delegate method has been called + // during pairing. Used to determine whether we need to log the + // "no pairing interaction" metric. + bool pairing_delegate_used_; + + // During pairing these callbacks are set to those provided by method calls + // made on the BluetoothAdapterChromeOS instance by its respective + // BluetoothAgentServiceProvider instance, and are called by our own + // method calls such as SetPinCode() and SetPasskey(). + PinCodeCallback pincode_callback_; + PasskeyCallback passkey_callback_; + ConfirmationCallback confirmation_callback_; + }; + + // Called by dbus:: on completion of the D-Bus method call to register the + // pairing agent. + void OnRegisterAgent(); + void OnRegisterAgentError(const std::string& error_name, + const std::string& error_message); + // Internal method used to locate the device object by object path // (the devices map and BluetoothDevice methods are by address) BluetoothDeviceChromeOS* GetDeviceWithPath( const dbus::ObjectPath& object_path); + // Internal method to obtain the ChromeOS BluetoothDevice object, returned in + // |device_chromeos| and associated PairingContext, returned in + // |pairing_context| for the device with path |object_path|. + // Returns true on success, false if device doesn't exist or there is no + // pairing context for it. + bool GetDeviceAndPairingContext(const dbus::ObjectPath& object_path, + BluetoothDeviceChromeOS** device_chromeos, + PairingContext** pairing_context); + // Set the tracked adapter to the one in |object_path|, this object will // subsequently operate on that adapter until it is removed. void SetAdapter(const dbus::ObjectPath& object_path); @@ -148,6 +262,10 @@ class BluetoothAdapterChromeOS // List of observers interested in event notifications from us. ObserverList<device::BluetoothAdapter::Observer> observers_; + // Instance of the D-Bus agent object used for pairing, initialized with + // our own class as its delegate. + scoped_ptr<BluetoothAgentServiceProvider> agent_; + // 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_device_chromeos.cc b/device/bluetooth/bluetooth_device_chromeos.cc index 76e2097..74f3c8a 100644 --- a/device/bluetooth/bluetooth_device_chromeos.cc +++ b/device/bluetooth/bluetooth_device_chromeos.cc @@ -9,8 +9,6 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "chromeos/dbus/bluetooth_adapter_client.h" -#include "chromeos/dbus/bluetooth_agent_manager_client.h" -#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/dbus_thread_manager.h" @@ -24,24 +22,6 @@ using device::BluetoothDevice; namespace { -// The agent path is relatively meaningless since BlueZ only supports one -// at time and will fail in an attempt to register another with "Already Exists" -// (which we fail in OnRegisterAgentError with ERROR_INPROGRESS). -const char kAgentPath[] = "/org/chromium/bluetooth_agent"; - -// Histogram enumerations for pairing methods. -enum UMAPairingMethod { - UMA_PAIRING_METHOD_NONE, - UMA_PAIRING_METHOD_REQUEST_PINCODE, - UMA_PAIRING_METHOD_REQUEST_PASSKEY, - UMA_PAIRING_METHOD_DISPLAY_PINCODE, - UMA_PAIRING_METHOD_DISPLAY_PASSKEY, - UMA_PAIRING_METHOD_CONFIRM_PASSKEY, - // NOTE: Add new pairing methods immediately above this line. Make sure to - // update the enum list in tools/histogram/histograms.xml accordinly. - UMA_PAIRING_METHOD_COUNT -}; - // Histogram enumerations for pairing results. enum UMAPairingResult { UMA_PAIRING_RESULT_SUCCESS, @@ -133,8 +113,6 @@ BluetoothDeviceChromeOS::BluetoothDeviceChromeOS( : adapter_(adapter), object_path_(object_path), num_connecting_calls_(0), - pairing_delegate_(NULL), - pairing_delegate_used_(false), weak_ptr_factory_(this) { } @@ -248,15 +226,15 @@ void BluetoothDeviceChromeOS::ProvidesServiceWithName( } bool BluetoothDeviceChromeOS::ExpectingPinCode() const { - return !pincode_callback_.is_null(); + return pairing_context_.get() && pairing_context_->ExpectingPinCode(); } bool BluetoothDeviceChromeOS::ExpectingPasskey() const { - return !passkey_callback_.is_null(); + return pairing_context_.get() && pairing_context_->ExpectingPasskey(); } bool BluetoothDeviceChromeOS::ExpectingConfirmation() const { - return !confirmation_callback_.is_null(); + return pairing_context_.get() && pairing_context_->ExpectingConfirmation(); } void BluetoothDeviceChromeOS::Connect( @@ -274,66 +252,55 @@ void BluetoothDeviceChromeOS::Connect( ConnectInternal(false, callback, error_callback); } else { // Initiate high-security connection with pairing. - DCHECK(!pairing_delegate_); - DCHECK(agent_.get() == NULL); - - pairing_delegate_ = pairing_delegate; - pairing_delegate_used_ = false; - - // The agent path is relatively meaningless since BlueZ only supports - // one per application at a time. - dbus::Bus* system_bus = DBusThreadManager::Get()->GetSystemBus(); - agent_.reset(BluetoothAgentServiceProvider::Create( - system_bus, dbus::ObjectPath(kAgentPath), this)); - DCHECK(agent_.get()); - - VLOG(1) << object_path_.value() << ": Registering agent for pairing"; - DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> - RegisterAgent( - dbus::ObjectPath(kAgentPath), - bluetooth_agent_manager::kKeyboardDisplayCapability, - base::Bind(&BluetoothDeviceChromeOS::OnRegisterAgent, - weak_ptr_factory_.GetWeakPtr(), - callback, - error_callback), - base::Bind(&BluetoothDeviceChromeOS::OnRegisterAgentError, - weak_ptr_factory_.GetWeakPtr(), - error_callback)); + DCHECK(!pairing_context_); + pairing_context_.reset( + new BluetoothAdapterChromeOS::PairingContext(pairing_delegate)); + + DBusThreadManager::Get()->GetBluetoothDeviceClient()-> + Pair(object_path_, + base::Bind(&BluetoothDeviceChromeOS::OnPair, + weak_ptr_factory_.GetWeakPtr(), + callback, error_callback), + base::Bind(&BluetoothDeviceChromeOS::OnPairError, + weak_ptr_factory_.GetWeakPtr(), + error_callback)); } } void BluetoothDeviceChromeOS::SetPinCode(const std::string& pincode) { - if (!agent_.get() || pincode_callback_.is_null()) + if (!pairing_context_.get()) return; - pincode_callback_.Run(SUCCESS, pincode); - pincode_callback_.Reset(); + pairing_context_->SetPinCode(pincode); } void BluetoothDeviceChromeOS::SetPasskey(uint32 passkey) { - if (!agent_.get() || passkey_callback_.is_null()) + if (!pairing_context_.get()) return; - passkey_callback_.Run(SUCCESS, passkey); - passkey_callback_.Reset(); + pairing_context_->SetPasskey(passkey); } void BluetoothDeviceChromeOS::ConfirmPairing() { - if (!agent_.get() || confirmation_callback_.is_null()) + if (!pairing_context_.get()) return; - confirmation_callback_.Run(SUCCESS); - confirmation_callback_.Reset(); + pairing_context_->ConfirmPairing(); } void BluetoothDeviceChromeOS::RejectPairing() { - RunPairingCallbacks(REJECTED); + if (!pairing_context_.get()) + return; + + pairing_context_->RejectPairing(); } void BluetoothDeviceChromeOS::CancelPairing() { // If there wasn't a callback in progress that we can reply to then we // have to send a CancelPairing() to the device instead. - if (!RunPairingCallbacks(CANCELLED)) { + if (!pairing_context_.get() || !pairing_context_->CancelPairing()) { + VLOG(1) << object_path_.value() << ": No pairing context or callback. " + << "Sending explicit cancel"; DBusThreadManager::Get()->GetBluetoothDeviceClient()-> CancelPairing( object_path_, @@ -342,8 +309,9 @@ void BluetoothDeviceChromeOS::CancelPairing() { weak_ptr_factory_.GetWeakPtr())); // Since there's no calback to this method, it's possible that the pairing - // delegate is going to be freed before things complete. - UnregisterAgent(); + // delegate is going to be freed before things complete, so clear out the + // context holding it. + pairing_context_.reset(); } } @@ -419,134 +387,6 @@ void BluetoothDeviceChromeOS::ClearOutOfBandPairingData( error_callback.Run(); } - -void BluetoothDeviceChromeOS::Release() { - DCHECK(agent_.get()); - DCHECK(pairing_delegate_); - VLOG(1) << object_path_.value() << ": Release"; - - pincode_callback_.Reset(); - passkey_callback_.Reset(); - confirmation_callback_.Reset(); - - UnregisterAgent(); -} - -void BluetoothDeviceChromeOS::RequestPinCode( - const dbus::ObjectPath& device_path, - const PinCodeCallback& callback) { - DCHECK(agent_.get()); - DCHECK(device_path == object_path_); - VLOG(1) << object_path_.value() << ": RequestPinCode"; - - UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", - UMA_PAIRING_METHOD_REQUEST_PINCODE, - UMA_PAIRING_METHOD_COUNT); - - DCHECK(pairing_delegate_); - DCHECK(pincode_callback_.is_null()); - pincode_callback_ = callback; - pairing_delegate_->RequestPinCode(this); - pairing_delegate_used_ = true; -} - -void BluetoothDeviceChromeOS::DisplayPinCode( - const dbus::ObjectPath& device_path, - const std::string& pincode) { - DCHECK(agent_.get()); - DCHECK(device_path == object_path_); - VLOG(1) << object_path_.value() << ": DisplayPinCode: " << pincode; - - UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", - UMA_PAIRING_METHOD_DISPLAY_PINCODE, - UMA_PAIRING_METHOD_COUNT); - - DCHECK(pairing_delegate_); - pairing_delegate_->DisplayPinCode(this, pincode); - pairing_delegate_used_ = true; -} - -void BluetoothDeviceChromeOS::RequestPasskey( - const dbus::ObjectPath& device_path, - const PasskeyCallback& callback) { - DCHECK(agent_.get()); - DCHECK(device_path == object_path_); - VLOG(1) << object_path_.value() << ": RequestPasskey"; - - UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", - UMA_PAIRING_METHOD_REQUEST_PASSKEY, - UMA_PAIRING_METHOD_COUNT); - - DCHECK(pairing_delegate_); - DCHECK(passkey_callback_.is_null()); - passkey_callback_ = callback; - pairing_delegate_->RequestPasskey(this); - pairing_delegate_used_ = true; -} - -void BluetoothDeviceChromeOS::DisplayPasskey( - const dbus::ObjectPath& device_path, - uint32 passkey, - uint16 entered) { - DCHECK(agent_.get()); - DCHECK(device_path == object_path_); - VLOG(1) << object_path_.value() << ": DisplayPasskey: " << passkey - << " (" << entered << " entered)"; - - if (entered == 0) - UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", - UMA_PAIRING_METHOD_DISPLAY_PASSKEY, - UMA_PAIRING_METHOD_COUNT); - - DCHECK(pairing_delegate_); - if (entered == 0) - pairing_delegate_->DisplayPasskey(this, passkey); - pairing_delegate_->KeysEntered(this, entered); - pairing_delegate_used_ = true; -} - -void BluetoothDeviceChromeOS::RequestConfirmation( - const dbus::ObjectPath& device_path, - uint32 passkey, - const ConfirmationCallback& callback) { - DCHECK(agent_.get()); - DCHECK(device_path == object_path_); - VLOG(1) << object_path_.value() << ": RequestConfirmation: " << passkey; - - UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", - UMA_PAIRING_METHOD_CONFIRM_PASSKEY, - UMA_PAIRING_METHOD_COUNT); - - DCHECK(pairing_delegate_); - DCHECK(confirmation_callback_.is_null()); - confirmation_callback_ = callback; - pairing_delegate_->ConfirmPasskey(this, passkey); - pairing_delegate_used_ = true; -} - -void BluetoothDeviceChromeOS::RequestAuthorization( - const dbus::ObjectPath& device_path, - const ConfirmationCallback& callback) { - // TODO(keybuk): implement - callback.Run(CANCELLED); -} - -void BluetoothDeviceChromeOS::AuthorizeService( - const dbus::ObjectPath& device_path, - const std::string& uuid, - const ConfirmationCallback& callback) { - // TODO(keybuk): implement - callback.Run(CANCELLED); -} - -void BluetoothDeviceChromeOS::Cancel() { - DCHECK(agent_.get()); - VLOG(1) << object_path_.value() << ": Cancel"; - - DCHECK(pairing_delegate_); - pairing_delegate_->DismissDisplayOrConfirm(); -} - void BluetoothDeviceChromeOS::ConnectInternal( bool after_pairing, const base::Closure& callback, @@ -613,55 +453,13 @@ void BluetoothDeviceChromeOS::OnConnectError( error_callback.Run(error_code); } -void BluetoothDeviceChromeOS::OnRegisterAgent( - const base::Closure& callback, - const ConnectErrorCallback& error_callback) { - VLOG(1) << object_path_.value() << ": Agent registered, now pairing"; - - DBusThreadManager::Get()->GetBluetoothDeviceClient()-> - Pair(object_path_, - base::Bind(&BluetoothDeviceChromeOS::OnPair, - weak_ptr_factory_.GetWeakPtr(), - callback, error_callback), - base::Bind(&BluetoothDeviceChromeOS::OnPairError, - weak_ptr_factory_.GetWeakPtr(), - error_callback)); -} - -void BluetoothDeviceChromeOS::OnRegisterAgentError( - const ConnectErrorCallback& error_callback, - const std::string& error_name, - const std::string& error_message) { - if (--num_connecting_calls_ == 0) - adapter_->NotifyDeviceChanged(this); - - DCHECK(num_connecting_calls_ >= 0); - LOG(WARNING) << object_path_.value() << ": Failed to register agent: " - << error_name << ": " << error_message; - VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ - << " still in progress"; - - UnregisterAgent(); - - // Determine the error code from error_name. - ConnectErrorCode error_code = ERROR_UNKNOWN; - if (error_name == bluetooth_agent_manager::kErrorAlreadyExists) - error_code = ERROR_INPROGRESS; - - RecordPairingResult(error_code); - error_callback.Run(error_code); -} - void BluetoothDeviceChromeOS::OnPair( const base::Closure& callback, const ConnectErrorCallback& error_callback) { VLOG(1) << object_path_.value() << ": Paired"; - if (!pairing_delegate_used_) - UMA_HISTOGRAM_ENUMERATION("Bluetooth.PairingMethod", - UMA_PAIRING_METHOD_NONE, - UMA_PAIRING_METHOD_COUNT); - UnregisterAgent(); + pairing_context_.reset(); + SetTrusted(); ConnectInternal(true, callback, error_callback); } @@ -679,7 +477,7 @@ void BluetoothDeviceChromeOS::OnPairError( VLOG(1) << object_path_.value() << ": " << num_connecting_calls_ << " still in progress"; - UnregisterAgent(); + pairing_context_.reset(); // Determine the error code from error_name. ConnectErrorCode error_code = ERROR_UNKNOWN; @@ -725,38 +523,6 @@ void BluetoothDeviceChromeOS::OnSetTrusted(bool success) { << ": Failed to set device as trusted"; } -void BluetoothDeviceChromeOS::UnregisterAgent() { - if (!agent_.get()) - return; - - DCHECK(pairing_delegate_); - - DCHECK(pincode_callback_.is_null()); - DCHECK(passkey_callback_.is_null()); - DCHECK(confirmation_callback_.is_null()); - - pairing_delegate_->DismissDisplayOrConfirm(); - pairing_delegate_ = NULL; - - agent_.reset(); - - // Clean up after ourselves. - VLOG(1) << object_path_.value() << ": Unregistering pairing agent"; - DBusThreadManager::Get()->GetBluetoothAgentManagerClient()-> - UnregisterAgent( - dbus::ObjectPath(kAgentPath), - base::Bind(&base::DoNothing), - base::Bind(&BluetoothDeviceChromeOS::OnUnregisterAgentError, - weak_ptr_factory_.GetWeakPtr())); -} - -void BluetoothDeviceChromeOS::OnUnregisterAgentError( - const std::string& error_name, - const std::string& error_message) { - LOG(WARNING) << object_path_.value() << ": Failed to unregister agent: " - << error_name << ": " << error_message; -} - void BluetoothDeviceChromeOS::OnDisconnect(const base::Closure& callback) { VLOG(1) << object_path_.value() << ": Disconnected"; callback.Run(); @@ -780,32 +546,6 @@ void BluetoothDeviceChromeOS::OnForgetError( error_callback.Run(); } -bool BluetoothDeviceChromeOS::RunPairingCallbacks(Status status) { - if (!agent_.get()) - return false; - - bool callback_run = false; - if (!pincode_callback_.is_null()) { - pincode_callback_.Run(status, ""); - pincode_callback_.Reset(); - callback_run = true; - } - - if (!passkey_callback_.is_null()) { - passkey_callback_.Run(status, 0); - passkey_callback_.Reset(); - callback_run = true; - } - - if (!confirmation_callback_.is_null()) { - confirmation_callback_.Run(status); - confirmation_callback_.Reset(); - callback_run = true; - } - - return callback_run; -} - void BluetoothDeviceChromeOS::OnConnectProfile( device::BluetoothProfile* profile, const base::Closure& callback) { diff --git a/device/bluetooth/bluetooth_device_chromeos.h b/device/bluetooth/bluetooth_device_chromeos.h index fef7cfd..e2f2997 100644 --- a/device/bluetooth/bluetooth_device_chromeos.h +++ b/device/bluetooth/bluetooth_device_chromeos.h @@ -9,20 +9,17 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "chromeos/dbus/bluetooth_agent_service_provider.h" #include "chromeos/dbus/bluetooth_device_client.h" #include "dbus/object_path.h" +#include "device/bluetooth/bluetooth_adapter_chromeos.h" #include "device/bluetooth/bluetooth_device.h" namespace chromeos { -class BluetoothAdapterChromeOS; - // The BluetoothDeviceChromeOS class implements BluetoothDevice for the // Chrome OS platform. class BluetoothDeviceChromeOS - : public device::BluetoothDevice, - private chromeos::BluetoothAgentServiceProvider::Delegate { + : public device::BluetoothDevice { public: // BluetoothDevice override virtual uint32 GetBluetoothClass() const OVERRIDE; @@ -83,28 +80,6 @@ class BluetoothDeviceChromeOS const dbus::ObjectPath& object_path); virtual ~BluetoothDeviceChromeOS(); - // BluetoothAgentServiceProvider::Delegate override. - virtual void Release() OVERRIDE; - virtual void RequestPinCode(const dbus::ObjectPath& device_path, - const PinCodeCallback& callback) OVERRIDE; - virtual void DisplayPinCode(const dbus::ObjectPath& device_path, - const std::string& pincode) OVERRIDE; - virtual void RequestPasskey(const dbus::ObjectPath& device_path, - const PasskeyCallback& callback) OVERRIDE; - virtual void DisplayPasskey(const dbus::ObjectPath& device_path, - uint32 passkey, uint16 entered) OVERRIDE; - virtual void RequestConfirmation(const dbus::ObjectPath& device_path, - uint32 passkey, - const ConfirmationCallback& callback) - OVERRIDE; - virtual void RequestAuthorization(const dbus::ObjectPath& device_path, - const ConfirmationCallback& callback) - OVERRIDE; - virtual void AuthorizeService(const dbus::ObjectPath& device_path, - const std::string& uuid, - const ConfirmationCallback& callback) OVERRIDE; - virtual void Cancel() OVERRIDE; - // Internal method to initiate a connection to this device, and methods called // by dbus:: on completion of the D-Bus method call. void ConnectInternal(bool after_pairing, @@ -117,14 +92,6 @@ class BluetoothDeviceChromeOS const std::string& error_name, const std::string& error_message); - // Called by dbus:: on completion of the D-Bus method call to register the - // pairing agent. - void OnRegisterAgent(const base::Closure& callback, - const ConnectErrorCallback& error_callback); - void OnRegisterAgentError(const ConnectErrorCallback& error_callback, - const std::string& error_name, - const std::string& error_message); - // Called by dbus:: on completion of the D-Bus method call to pair the device. void OnPair(const base::Closure& callback, const ConnectErrorCallback& error_callback); @@ -145,13 +112,6 @@ class BluetoothDeviceChromeOS void SetTrusted(); void OnSetTrusted(bool success); - // Internal method to unregister the pairing agent and method called by dbus:: - // on failure of the D-Bus method call. No completion call as success is - // ignored. - void UnregisterAgent(); - void OnUnregisterAgentError(const std::string& error_name, - const std::string& error_message); - // Called by dbus:: on completion of the D-Bus method call to disconnect the // device. void OnDisconnect(const base::Closure& callback); @@ -166,10 +126,6 @@ class BluetoothDeviceChromeOS const std::string& error_name, const std::string& error_message); - // Run any outstanding pairing callbacks passing |status| as the result of - // pairing. Returns true if any callbacks were run, false if not. - bool RunPairingCallbacks(Status status); - // Called by dbus:: on completion of the D-Bus method call to // connect a peofile. void OnConnectProfile(device::BluetoothProfile* profile, @@ -196,20 +152,7 @@ class BluetoothDeviceChromeOS // Passkeys. Generally it is the object that owns this one. PairingDelegate* pairing_delegate_; - // Flag to indicate whether a pairing delegate method has been called during - // pairing. - bool pairing_delegate_used_; - - // During pairing this is set to an instance of a D-Bus agent object - // intialized with our own class as its delegate. - scoped_ptr<BluetoothAgentServiceProvider> agent_; - - // During pairing these callbacks are set to those provided by method calls - // made on us by |agent_| and are called by our own method calls such as - // SetPinCode() and SetPasskey(). - PinCodeCallback pincode_callback_; - PasskeyCallback passkey_callback_; - ConfirmationCallback confirmation_callback_; + scoped_ptr<BluetoothAdapterChromeOS::PairingContext> pairing_context_; // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. diff --git a/device/bluetooth/bluetooth_profile_chromeos_unittest.cc b/device/bluetooth/bluetooth_profile_chromeos_unittest.cc index dd7c945..da2f659 100644 --- a/device/bluetooth/bluetooth_profile_chromeos_unittest.cc +++ b/device/bluetooth/bluetooth_profile_chromeos_unittest.cc @@ -4,6 +4,7 @@ #include "base/message_loop/message_loop.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_input_client.h" #include "chromeos/dbus/fake_bluetooth_profile_manager_client.h" @@ -45,6 +46,9 @@ class BluetoothProfileChromeOSTest : public testing::Test { fake_dbus_thread_manager->SetBluetoothProfileManagerClient( scoped_ptr<BluetoothProfileManagerClient>( fake_bluetooth_profile_manager_client_)); + fake_dbus_thread_manager->SetBluetoothAgentManagerClient( + scoped_ptr<BluetoothAgentManagerClient>( + new FakeBluetoothAgentManagerClient)); fake_dbus_thread_manager->SetBluetoothAdapterClient( scoped_ptr<BluetoothAdapterClient>(new FakeBluetoothAdapterClient)); fake_dbus_thread_manager->SetBluetoothDeviceClient( |