diff options
Diffstat (limited to 'device/bluetooth/bluetooth_adapter_chromeos.cc')
-rw-r--r-- | device/bluetooth/bluetooth_adapter_chromeos.cc | 336 |
1 files changed, 336 insertions, 0 deletions
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; |