Commit 5902a7fc authored by isherman@chromium.org's avatar isherman@chromium.org

[Bluetooth] Improve the adapter's awareness of connected devices.

Inform the adapter when a new, potentially unpaired device connects.
In addition to notifying any observers of this event, this prevents a
NULL pointer dereference in the existing logic.

BUG=385493
TEST=Establish a Bluetooth connection from an unpaired device.
     chrome.bluetooth.onDeviceAdded() should be called.
R=keybuk@chromium.org

Review URL: https://codereview.chromium.org/341433004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278050 0039d316-1c4b-4281-b951-d872f2087c98
parent ef827520
...@@ -75,6 +75,9 @@ class BluetoothAdapterMac : public BluetoothAdapter, ...@@ -75,6 +75,9 @@ class BluetoothAdapterMac : public BluetoothAdapter,
virtual void DiscoveryStopped(BluetoothDiscoveryManagerMac* manager, virtual void DiscoveryStopped(BluetoothDiscoveryManagerMac* manager,
bool unexpected) OVERRIDE; bool unexpected) OVERRIDE;
// Registers that a new |device| has connected to the local host.
void DeviceConnected(IOBluetoothDevice* device);
protected: protected:
// BluetoothAdapter: // BluetoothAdapter:
virtual void RemovePairingDelegateInternal( virtual void RemovePairingDelegateInternal(
...@@ -98,8 +101,10 @@ class BluetoothAdapterMac : public BluetoothAdapter, ...@@ -98,8 +101,10 @@ class BluetoothAdapterMac : public BluetoothAdapter,
void InitForTest(scoped_refptr<base::SequencedTaskRunner> ui_task_runner); void InitForTest(scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
void PollAdapter(); void PollAdapter();
// Updates |devices_| to be consistent with |devices|. // Updates |devices_| to include the currently paired devices, as well as any
void UpdateDevices(NSArray* devices); // connected, but unpaired, devices. Notifies observers if any previously
// paired or connected devices are no longer present.
void UpdateDevices();
std::string address_; std::string address_;
std::string name_; std::string name_;
......
...@@ -138,6 +138,10 @@ void BluetoothAdapterMac::CreateL2capService( ...@@ -138,6 +138,10 @@ void BluetoothAdapterMac::CreateL2capService(
void BluetoothAdapterMac::DeviceFound(BluetoothDiscoveryManagerMac* manager, void BluetoothAdapterMac::DeviceFound(BluetoothDiscoveryManagerMac* manager,
IOBluetoothDevice* device) { IOBluetoothDevice* device) {
// TODO(isherman): The list of discovered devices is never reset. This should
// probably key off of |devices_| instead. Currently, if a device is paired,
// then unpaired, then paired again, the app would never hear about the second
// pairing.
std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
if (discovered_devices_.find(device_address) == discovered_devices_.end()) { if (discovered_devices_.find(device_address) == discovered_devices_.end()) {
BluetoothDeviceMac device_mac(device); BluetoothDeviceMac device_mac(device);
...@@ -161,6 +165,25 @@ void BluetoothAdapterMac::DiscoveryStopped( ...@@ -161,6 +165,25 @@ void BluetoothAdapterMac::DiscoveryStopped(
AdapterDiscoveringChanged(this, false)); AdapterDiscoveringChanged(this, false));
} }
void BluetoothAdapterMac::DeviceConnected(IOBluetoothDevice* device) {
// TODO(isherman): Call -registerForDisconnectNotification:selector:, and
// investigate whether this method can be replaced with a call to
// +registerForConnectNotifications:selector:.
std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
DVLOG(1) << "Adapter registered a new connection from device with address: "
<< device_address;
// Only notify once per device.
if (devices_.count(device_address))
return;
scoped_ptr<BluetoothDeviceMac> device_mac(new BluetoothDeviceMac(device));
FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
observers_,
DeviceAdded(this, device_mac.get()));
devices_[device_address] = device_mac.release();
}
void BluetoothAdapterMac::AddDiscoverySession( void BluetoothAdapterMac::AddDiscoverySession(
const base::Closure& callback, const base::Closure& callback,
const ErrorCallback& error_callback) { const ErrorCallback& error_callback) {
...@@ -262,6 +285,7 @@ void BluetoothAdapterMac::PollAdapter() { ...@@ -262,6 +285,7 @@ void BluetoothAdapterMac::PollAdapter() {
AdapterPoweredChanged(this, powered_)); AdapterPoweredChanged(this, powered_));
} }
// TODO(isherman): This doesn't detect when a device is unpaired.
IOBluetoothDevice* recent_device = IOBluetoothDevice* recent_device =
[[IOBluetoothDevice recentDevices:1] lastObject]; [[IOBluetoothDevice recentDevices:1] lastObject];
NSDate* access_timestamp = [recent_device recentAccessDate]; NSDate* access_timestamp = [recent_device recentAccessDate];
...@@ -269,7 +293,7 @@ void BluetoothAdapterMac::PollAdapter() { ...@@ -269,7 +293,7 @@ void BluetoothAdapterMac::PollAdapter() {
access_timestamp == nil || access_timestamp == nil ||
[recently_accessed_device_timestamp_ compare:access_timestamp] == [recently_accessed_device_timestamp_ compare:access_timestamp] ==
NSOrderedAscending) { NSOrderedAscending) {
UpdateDevices([IOBluetoothDevice pairedDevices]); UpdateDevices();
recently_accessed_device_timestamp_.reset([access_timestamp copy]); recently_accessed_device_timestamp_.reset([access_timestamp copy]);
} }
...@@ -280,15 +304,39 @@ void BluetoothAdapterMac::PollAdapter() { ...@@ -280,15 +304,39 @@ void BluetoothAdapterMac::PollAdapter() {
base::TimeDelta::FromMilliseconds(kPollIntervalMs)); base::TimeDelta::FromMilliseconds(kPollIntervalMs));
} }
void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { void BluetoothAdapterMac::UpdateDevices() {
// TODO(armansito): This code never calls // Snapshot the devices observers were previously notified of.
// BluetoothAdapter::Observer::DeviceRemoved. It should, if a device // Note that the code below is careful to take ownership of any values that
// no longer exists. // are erased from the map, since the map owns the memory for all its mapped
STLDeleteValues(&devices_); // devices.
for (IOBluetoothDevice* device in devices) { DevicesMap old_devices = devices_;
// Add all the paired devices.
devices_.clear();
for (IOBluetoothDevice* device in [IOBluetoothDevice pairedDevices]) {
std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device);
devices_[device_address] = new BluetoothDeviceMac(device); scoped_ptr<BluetoothDevice> device_mac(old_devices[device_address]);
if (!device_mac)
device_mac.reset(new BluetoothDeviceMac(device));
devices_[device_address] = device_mac.release();
old_devices.erase(device_address);
}
// Add any unpaired connected devices.
for (const auto& old_device : old_devices) {
if (!old_device.second->IsConnected())
continue;
const std::string& device_address = old_device.first;
DCHECK(!devices_.count(device_address));
devices_[device_address] = old_device.second;
old_devices.erase(device_address);
} }
// TODO(isherman): Notify observers of any devices that are no longer in
// range. Note that it's possible for a device to be neither paired nor
// connected, but to still be in range.
STLDeleteValues(&old_devices);
} }
} // namespace device } // namespace device
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "base/macros.h" #include "base/macros.h"
@class IOBluetoothDevice;
namespace device { namespace device {
class BluetoothSocketMac; class BluetoothSocketMac;
...@@ -28,7 +30,10 @@ class BluetoothChannelMac { ...@@ -28,7 +30,10 @@ class BluetoothChannelMac {
// Returns the Bluetooth address for the device associated with |this| // Returns the Bluetooth address for the device associated with |this|
// channel. // channel.
virtual std::string GetDeviceAddress() = 0; std::string GetDeviceAddress();
// Returns the Bluetooth device associated with |this| channel.
virtual IOBluetoothDevice* GetDevice() = 0;
// Returns the outgoing MTU (maximum transmission unit) for the channel. // Returns the outgoing MTU (maximum transmission unit) for the channel.
virtual uint16_t GetOutgoingMTU() = 0; virtual uint16_t GetOutgoingMTU() = 0;
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
#include "device/bluetooth/bluetooth_channel_mac.h" #include "device/bluetooth/bluetooth_channel_mac.h"
#import <IOBluetooth/IOBluetooth.h>
#include "base/logging.h" #include "base/logging.h"
#include "device/bluetooth/bluetooth_device_mac.h"
namespace device { namespace device {
...@@ -19,4 +22,8 @@ void BluetoothChannelMac::SetSocket(BluetoothSocketMac* socket) { ...@@ -19,4 +22,8 @@ void BluetoothChannelMac::SetSocket(BluetoothSocketMac* socket) {
socket_ = socket; socket_ = socket;
} }
std::string BluetoothChannelMac::GetDeviceAddress() {
return BluetoothDeviceMac::GetDeviceAddress(GetDevice());
}
} // namespace device } // namespace device
...@@ -38,7 +38,7 @@ class BluetoothL2capChannelMac : public BluetoothChannelMac { ...@@ -38,7 +38,7 @@ class BluetoothL2capChannelMac : public BluetoothChannelMac {
// BluetoothChannelMac: // BluetoothChannelMac:
virtual void SetSocket(BluetoothSocketMac* socket) OVERRIDE; virtual void SetSocket(BluetoothSocketMac* socket) OVERRIDE;
virtual std::string GetDeviceAddress() OVERRIDE; virtual IOBluetoothDevice* GetDevice() OVERRIDE;
virtual uint16_t GetOutgoingMTU() OVERRIDE; virtual uint16_t GetOutgoingMTU() OVERRIDE;
virtual IOReturn WriteAsync(void* data, virtual IOReturn WriteAsync(void* data,
uint16_t length, uint16_t length,
......
...@@ -115,8 +115,8 @@ void BluetoothL2capChannelMac::SetSocket(BluetoothSocketMac* socket) { ...@@ -115,8 +115,8 @@ void BluetoothL2capChannelMac::SetSocket(BluetoothSocketMac* socket) {
[channel_ setDelegate:delegate_]; [channel_ setDelegate:delegate_];
} }
std::string BluetoothL2capChannelMac::GetDeviceAddress() { IOBluetoothDevice* BluetoothL2capChannelMac::GetDevice() {
return BluetoothDeviceMac::GetDeviceAddress([channel_ getDevice]); return [channel_ getDevice];
} }
uint16_t BluetoothL2capChannelMac::GetOutgoingMTU() { uint16_t BluetoothL2capChannelMac::GetOutgoingMTU() {
......
...@@ -38,7 +38,7 @@ class BluetoothRfcommChannelMac : public BluetoothChannelMac { ...@@ -38,7 +38,7 @@ class BluetoothRfcommChannelMac : public BluetoothChannelMac {
// BluetoothChannelMac: // BluetoothChannelMac:
virtual void SetSocket(BluetoothSocketMac* socket) OVERRIDE; virtual void SetSocket(BluetoothSocketMac* socket) OVERRIDE;
virtual std::string GetDeviceAddress() OVERRIDE; virtual IOBluetoothDevice* GetDevice() OVERRIDE;
virtual uint16_t GetOutgoingMTU() OVERRIDE; virtual uint16_t GetOutgoingMTU() OVERRIDE;
virtual IOReturn WriteAsync(void* data, virtual IOReturn WriteAsync(void* data,
uint16_t length, uint16_t length,
......
...@@ -110,8 +110,8 @@ void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) { ...@@ -110,8 +110,8 @@ void BluetoothRfcommChannelMac::SetSocket(BluetoothSocketMac* socket) {
[channel_ setDelegate:delegate_]; [channel_ setDelegate:delegate_];
} }
std::string BluetoothRfcommChannelMac::GetDeviceAddress() { IOBluetoothDevice* BluetoothRfcommChannelMac::GetDevice() {
return BluetoothDeviceMac::GetDeviceAddress([channel_ getDevice]); return [channel_ getDevice];
} }
uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() { uint16_t BluetoothRfcommChannelMac::GetOutgoingMTU() {
......
...@@ -29,7 +29,7 @@ class IOBufferWithSize; ...@@ -29,7 +29,7 @@ class IOBufferWithSize;
namespace device { namespace device {
class BluetoothAdapter; class BluetoothAdapterMac;
class BluetoothChannelMac; class BluetoothChannelMac;
// Implements the BluetoothSocket class for the Mac OS X platform. // Implements the BluetoothSocket class for the Mac OS X platform.
...@@ -52,7 +52,7 @@ class BluetoothSocketMac : public BluetoothSocket { ...@@ -52,7 +52,7 @@ class BluetoothSocketMac : public BluetoothSocket {
// |success_callback| will be called if the service is successfully // |success_callback| will be called if the service is successfully
// registered, |error_callback| on failure with a message explaining the // registered, |error_callback| on failure with a message explaining the
// cause. // cause.
void ListenUsingRfcomm(scoped_refptr<BluetoothAdapter> adapter, void ListenUsingRfcomm(scoped_refptr<BluetoothAdapterMac> adapter,
const BluetoothUUID& uuid, const BluetoothUUID& uuid,
int channel_id, int channel_id,
const base::Closure& success_callback, const base::Closure& success_callback,
...@@ -63,7 +63,7 @@ class BluetoothSocketMac : public BluetoothSocket { ...@@ -63,7 +63,7 @@ class BluetoothSocketMac : public BluetoothSocket {
// |success_callback| will be called if the service is successfully // |success_callback| will be called if the service is successfully
// registered, |error_callback| on failure with a message explaining the // registered, |error_callback| on failure with a message explaining the
// cause. // cause.
void ListenUsingL2cap(scoped_refptr<BluetoothAdapter> adapter, void ListenUsingL2cap(scoped_refptr<BluetoothAdapterMac> adapter,
const BluetoothUUID& uuid, const BluetoothUUID& uuid,
int psm, int psm,
const base::Closure& success_callback, const base::Closure& success_callback,
...@@ -155,7 +155,7 @@ class BluetoothSocketMac : public BluetoothSocket { ...@@ -155,7 +155,7 @@ class BluetoothSocketMac : public BluetoothSocket {
// Adapter the socket is registered against. This is only present when the // Adapter the socket is registered against. This is only present when the
// socket is listening. // socket is listening.
scoped_refptr<BluetoothAdapter> adapter_; scoped_refptr<BluetoothAdapterMac> adapter_;
// UUID of the profile being connected to, or that the socket is listening on. // UUID of the profile being connected to, or that the socket is listening on.
device::BluetoothUUID uuid_; device::BluetoothUUID uuid_;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_mac.h"
#include "device/bluetooth/bluetooth_channel_mac.h" #include "device/bluetooth/bluetooth_channel_mac.h"
#include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_device_mac.h" #include "device/bluetooth/bluetooth_device_mac.h"
...@@ -466,7 +467,7 @@ void BluetoothSocketMac::Connect( ...@@ -466,7 +467,7 @@ void BluetoothSocketMac::Connect(
} }
void BluetoothSocketMac::ListenUsingRfcomm( void BluetoothSocketMac::ListenUsingRfcomm(
scoped_refptr<BluetoothAdapter> adapter, scoped_refptr<BluetoothAdapterMac> adapter,
const BluetoothUUID& uuid, const BluetoothUUID& uuid,
int channel_id, int channel_id,
const base::Closure& success_callback, const base::Closure& success_callback,
...@@ -494,7 +495,7 @@ void BluetoothSocketMac::ListenUsingRfcomm( ...@@ -494,7 +495,7 @@ void BluetoothSocketMac::ListenUsingRfcomm(
} }
void BluetoothSocketMac::ListenUsingL2cap( void BluetoothSocketMac::ListenUsingL2cap(
scoped_refptr<BluetoothAdapter> adapter, scoped_refptr<BluetoothAdapterMac> adapter,
const BluetoothUUID& uuid, const BluetoothUUID& uuid,
int psm, int psm,
const base::Closure& success_callback, const base::Closure& success_callback,
...@@ -575,7 +576,7 @@ void BluetoothSocketMac::OnSDPQueryComplete( ...@@ -575,7 +576,7 @@ void BluetoothSocketMac::OnSDPQueryComplete(
} }
// Note: It's important to set the connect callbacks *prior* to opening the // Note: It's important to set the connect callbacks *prior* to opening the
// channel as the delegate is passed in and can synchronously call into // channel, as opening the channel can synchronously call into
// OnChannelOpenComplete(). // OnChannelOpenComplete().
connect_callbacks_.reset(new ConnectCallbacks()); connect_callbacks_.reset(new ConnectCallbacks());
connect_callbacks_->success_callback = success_callback; connect_callbacks_->success_callback = success_callback;
...@@ -590,6 +591,7 @@ void BluetoothSocketMac::OnSDPQueryComplete( ...@@ -590,6 +591,7 @@ void BluetoothSocketMac::OnSDPQueryComplete(
BluetoothL2capChannelMac::OpenAsync(this, device, l2cap_psm, &status); BluetoothL2capChannelMac::OpenAsync(this, device, l2cap_psm, &status);
} }
if (status != kIOReturnSuccess) { if (status != kIOReturnSuccess) {
ReleaseChannel();
std::stringstream error; std::stringstream error;
error << "Failed to connect bluetooth socket (" error << "Failed to connect bluetooth socket ("
<< BluetoothDeviceMac::GetDeviceAddress(device) << "): (" << status << BluetoothDeviceMac::GetDeviceAddress(device) << "): (" << status
...@@ -854,8 +856,7 @@ void BluetoothSocketMac::AcceptConnectionRequest() { ...@@ -854,8 +856,7 @@ void BluetoothSocketMac::AcceptConnectionRequest() {
linked_ptr<BluetoothChannelMac> channel = accept_queue_.front(); linked_ptr<BluetoothChannelMac> channel = accept_queue_.front();
accept_queue_.pop(); accept_queue_.pop();
// TODO(isherman): It isn't guaranteed that the adapter knows about the device adapter_->DeviceConnected(channel->GetDevice());
// at this point. Fix this logic.
BluetoothDevice* device = adapter_->GetDevice(channel->GetDeviceAddress()); BluetoothDevice* device = adapter_->GetDevice(channel->GetDeviceAddress());
DCHECK(device); DCHECK(device);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment