OSDN Git Service

service: Add connection state tracking to Adapter
authorArman Uguray <armansito@google.com>
Fri, 13 Nov 2015 23:05:48 +0000 (15:05 -0800)
committerArman Uguray <armansito@google.com>
Sat, 12 Dec 2015 00:17:30 +0000 (16:17 -0800)
Added the IsDeviceConnected method to Adapter and also an
Observer method that other components can use to track the ACL
state between the local adapter and a remote device.

Bug: 25157450
Change-Id: If9bc25ab58b4a9b5430753405fb64834c0946050

service/adapter.cpp
service/adapter.h
service/hal/bluetooth_gatt_interface.cpp
service/hal/bluetooth_interface.cpp
service/hal/bluetooth_interface.h
service/hal/fake_bluetooth_interface.cpp
service/hal/fake_bluetooth_interface.h
service/test/adapter_unittest.cpp

index 74a4906..222dc07 100644 (file)
@@ -42,6 +42,11 @@ void Adapter::Observer::OnAdapterStateChanged(Adapter* adapter,
   // Default implementation does nothing
 }
 
+void Adapter::Observer::OnDeviceConnectionStateChanged(
+    Adapter* adapter, const std::string& device_address, bool connected) {
+  // Default implementation does nothing
+}
+
 Adapter::Adapter()
     : state_(ADAPTER_STATE_OFF),
       address_(kDefaultAddress),
@@ -162,6 +167,11 @@ bool Adapter::IsMultiAdvertisementSupported() const {
   return local_le_features_.max_adv_instance >= kMinAdvInstancesForMultiAdv;
 }
 
+bool Adapter::IsDeviceConnected(const std::string& device_address) {
+  std::lock_guard<std::mutex> lock(connected_devices_lock_);
+  return connected_devices_.find(device_address) != connected_devices_.end();
+}
+
 LowEnergyClientFactory* Adapter::GetLowEnergyClientFactory() const {
   return ble_client_factory_.get();
 }
@@ -244,6 +254,37 @@ void Adapter::AdapterPropertiesCallback(bt_status_t status,
   }
 }
 
+void Adapter::AclStateChangedCallback(bt_status_t status,
+                                      const bt_bdaddr_t& remote_bdaddr,
+                                      bt_acl_state_t state) {
+  std::string device_address = BtAddrString(&remote_bdaddr);
+  bool connected = (state == BT_ACL_STATE_CONNECTED);
+  LOG(INFO) << "ACL state changed: " << device_address << " - connected: "
+            << (connected ? "true" : "false");
+
+  // If this is reported with an error status, I suppose the best thing we can
+  // do is to log it and ignore the event.
+  if (status != BT_STATUS_SUCCESS) {
+    LOG(ERROR) << "AclStateChangedCallback called with status: "
+               << BtStatusText(status);
+    return;
+  }
+
+  // Introduce a scope to manage |connected_devices_lock_| with RAII.
+  {
+    std::lock_guard<std::mutex> lock(connected_devices_lock_);
+    if (connected)
+      connected_devices_.insert(device_address);
+    else
+      connected_devices_.erase(device_address);
+  }
+
+  std::lock_guard<std::mutex> lock(observers_lock_);
+  FOR_EACH_OBSERVER(
+      Observer, observers_,
+      OnDeviceConnectionStateChanged(this, device_address, connected));
+}
+
 bool Adapter::SetAdapterProperty(bt_property_type_t type,
                                  void* value, int length) {
   CHECK(length > 0);
index 5cd3988..b73afe9 100644 (file)
@@ -19,6 +19,7 @@
 #include <atomic>
 #include <mutex>
 #include <string>
+#include <unordered_set>
 
 #include <base/macros.h>
 #include <base/observer_list.h>
@@ -44,13 +45,25 @@ class Adapter : public hal::BluetoothInterface::Observer {
   // Observer interface allows other classes to receive notifications from us.
   // All of the methods in this interface are declared as optional to allow
   // different layers to process only those events that they are interested in.
+  //
+  // All methods take in an |adapter| argument which points to the Adapter
+  // object that the Observer instance was added to.
   class Observer {
    public:
     virtual ~Observer() = default;
 
+    // Called when there is a change in the state of the local Bluetooth
+    // |adapter| from |prev_state| to |new_state|.
     virtual void OnAdapterStateChanged(Adapter* adapter,
                                        AdapterState prev_state,
                                        AdapterState new_state);
+
+    // Called when there is a change in the connection state between the local
+    // |adapter| and a remote device with address |device_address|. If the ACL
+    // state changes from disconnected to connected, then |connected| will be
+    // true and vice versa.
+    virtual void OnDeviceConnectionStateChanged(
+        Adapter* adapter, const std::string& device_address, bool connected);
   };
 
   Adapter();
@@ -91,6 +104,11 @@ class Adapter : public hal::BluetoothInterface::Observer {
   // multi-advertisement feature.
   bool IsMultiAdvertisementSupported() const;
 
+  // Returns true if the remote device with address |device_address| is
+  // currently connected. This is not a const method as it modifies the state of
+  // the associated internal mutex.
+  bool IsDeviceConnected(const std::string& device_address);
+
   // Returns a pointer to the LowEnergyClientFactory. This can be used to
   // register per-application LowEnergyClient instances to perform BLE GAP
   // operations.
@@ -110,6 +128,9 @@ class Adapter : public hal::BluetoothInterface::Observer {
   void AdapterPropertiesCallback(bt_status_t status,
                                  int num_properties,
                                  bt_property_t* properties) override;
+  void AclStateChangedCallback(bt_status_t status,
+                               const bt_bdaddr_t& remote_bdaddr,
+                               bt_acl_state_t state) override;
 
   // Sends a request to set the given HAL adapter property type and value.
   bool SetAdapterProperty(bt_property_type_t type, void* value, int length);
@@ -137,6 +158,10 @@ class Adapter : public hal::BluetoothInterface::Observer {
   std::mutex observers_lock_;
   base::ObserverList<Observer> observers_;
 
+  // List of devices addresses that are currently connected.
+  std::mutex connected_devices_lock_;
+  std::unordered_set<std::string> connected_devices_;
+
   // Factory used to create per-app LowEnergyClient instances.
   std::unique_ptr<LowEnergyClientFactory> ble_client_factory_;
 
index 8eee886..a039841 100644 (file)
@@ -53,10 +53,12 @@ base::ObserverList<BluetoothGattInterface::ServerObserver>*
                     *GetServerObservers(), func)
 
 #define VERIFY_INTERFACE_OR_RETURN() \
-  if (!g_interface) { \
-    LOG(WARNING) << "Callback received after |g_interface| is NULL"; \
-    return; \
-  }
+  do { \
+    if (!g_interface) { \
+      LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+      return; \
+    } \
+  } while (0)
 
 void RegisterClientCallback(int status, int client_if, bt_uuid_t* app_uuid) {
   lock_guard<mutex> lock(g_instance_lock);
index b8d99e6..7a4fc4c 100644 (file)
@@ -53,13 +53,17 @@ base::ObserverList<BluetoothInterface::Observer>* GetObservers();
 #define FOR_EACH_BLUETOOTH_OBSERVER(func) \
   FOR_EACH_OBSERVER(BluetoothInterface::Observer, *GetObservers(), func)
 
+#define VERIFY_INTERFACE_OR_RETURN() \
+  do { \
+    if (!g_bluetooth_interface) { \
+      LOG(WARNING) << "Callback received while |g_interface| is NULL"; \
+      return; \
+    } \
+  } while (0)
+
 void AdapterStateChangedCallback(bt_state_t state) {
   lock_guard<mutex> lock(g_instance_lock);
-  if (!g_bluetooth_interface) {
-    LOG(WARNING) << "Callback received after global instance was destroyed";
-    return;
-  }
-
+  VERIFY_INTERFACE_OR_RETURN();
   VLOG(1) << "Adapter state changed: " << BtStateText(state);
   FOR_EACH_BLUETOOTH_OBSERVER(AdapterStateChangedCallback(state));
 }
@@ -68,11 +72,7 @@ void AdapterPropertiesCallback(bt_status_t status,
                                int num_properties,
                                bt_property_t* properties) {
   lock_guard<mutex> lock(g_instance_lock);
-  if (!g_bluetooth_interface) {
-    LOG(WARNING) << "Callback received after global instance was destroyed";
-    return;
-  }
-
+  VERIFY_INTERFACE_OR_RETURN();
   VLOG(1) << "Adapter properties changed - status: " << BtStatusText(status)
           << ", num_properties: " << num_properties;
   FOR_EACH_BLUETOOTH_OBSERVER(
@@ -81,15 +81,26 @@ void AdapterPropertiesCallback(bt_status_t status,
 
 void DiscoveryStateChangedCallback(bt_discovery_state_t state) {
   lock_guard<mutex> lock(g_instance_lock);
-  if (!g_bluetooth_interface) {
-    LOG(WARNING) << "Callback received after global instance was destroyed";
-    return;
-  }
-
+  VERIFY_INTERFACE_OR_RETURN();
   VLOG(1) << "Discovery state changed - state: " << BtDiscoveryStateText(state);
   FOR_EACH_BLUETOOTH_OBSERVER(DiscoveryStateChangedCallback(state));
 }
 
+void AclStateChangedCallback(bt_status_t status,
+                             bt_bdaddr_t *remote_bd_addr,
+                             bt_acl_state_t state) {
+  lock_guard<mutex> lock(g_instance_lock);
+  VERIFY_INTERFACE_OR_RETURN();
+  CHECK(remote_bd_addr);
+  VLOG(1) << "Remote device ACL state changed - status: "
+          << BtStatusText(status)
+          << " - BD_ADDR: " << BtAddrString(remote_bd_addr)
+          << " - state: "
+          << ((state == BT_ACL_STATE_CONNECTED) ? "CONNECTED" : "DISCONNECTED");
+  FOR_EACH_BLUETOOTH_OBSERVER(
+      AclStateChangedCallback(status, *remote_bd_addr, state));
+}
+
 void ThreadEventCallback(bt_cb_thread_evt evt) {
   VLOG(1) << "ThreadEventCallback" << BtEventText(evt);
 
@@ -136,7 +147,7 @@ bt_callbacks_t bt_callbacks = {
   nullptr, /* pin_request_cb  */
   nullptr, /* ssp_request_cb  */
   nullptr, /* bond_state_changed_cb */
-  nullptr, /* acl_state_changed_cb */
+  AclStateChangedCallback,
   ThreadEventCallback,
   nullptr, /* dut_mode_recv_cb */
   nullptr, /* le_test_mode_cb */
@@ -275,6 +286,13 @@ void BluetoothInterface::Observer::DiscoveryStateChangedCallback(
   // Do nothing.
 }
 
+void BluetoothInterface::Observer::AclStateChangedCallback(
+    bt_status_t /* status */,
+    const bt_bdaddr_t& /* remote_bdaddr */,
+    bt_acl_state_t /* state */) {
+  // Do nothing.
+}
+
 // static
 bool BluetoothInterface::Initialize() {
   lock_guard<mutex> lock(g_instance_lock);
index 5fbef87..9b6d049 100644 (file)
@@ -54,6 +54,9 @@ class BluetoothInterface {
                                            int num_properties,
                                            bt_property_t* properties);
     virtual void DiscoveryStateChangedCallback(bt_discovery_state_t state);
+    virtual void AclStateChangedCallback(bt_status_t status,
+                                         const bt_bdaddr_t& remote_bdaddr,
+                                         bt_acl_state_t state);
 
     // TODO(armansito): Complete the list of callbacks.
   };
index 6a2309c..3dec807 100644 (file)
@@ -134,6 +134,15 @@ void FakeBluetoothInterface::NotifyAdapterLocalLeFeaturesPropertyChanged(
   NotifyAdapterPropertiesChanged(1, &property);
 }
 
+void FakeBluetoothInterface::NotifyAclStateChangedCallback(
+    bt_status_t status,
+    const bt_bdaddr_t& remote_bdaddr,
+    bt_acl_state_t state) {
+  FOR_EACH_OBSERVER(
+      Observer, observers_,
+      AclStateChangedCallback(status, remote_bdaddr, state));
+}
+
 void FakeBluetoothInterface::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
 }
index f77799f..553d4e0 100644 (file)
@@ -54,6 +54,10 @@ class FakeBluetoothInterface : public BluetoothInterface {
   void NotifyAdapterAddressPropertyChanged(const bt_bdaddr_t* address);
   void NotifyAdapterLocalLeFeaturesPropertyChanged(
       const bt_local_le_features_t* features);
+  void NotifyAclStateChangedCallback(
+      bt_status_t status,
+      const bt_bdaddr_t& remote_bdaddr,
+      bt_acl_state_t state);
 
   // hal::BluetoothInterface overrides:
   void AddObserver(Observer* observer) override;
index cfc2998..7d25163 100644 (file)
@@ -18,6 +18,7 @@
 #include <gtest/gtest.h>
 
 #include "service/adapter.h"
+#include "service/common/bluetooth/util/address_helper.h"
 #include "service/hal/fake_bluetooth_gatt_interface.h"
 #include "service/hal/fake_bluetooth_interface.h"
 
@@ -61,7 +62,8 @@ class TestObserver final : public bluetooth::Adapter::Observer {
   TestObserver(bluetooth::Adapter* adapter)
       : adapter_(adapter),
         prev_state_(bluetooth::ADAPTER_STATE_INVALID),
-        cur_state_(bluetooth::ADAPTER_STATE_INVALID) {
+        cur_state_(bluetooth::ADAPTER_STATE_INVALID),
+        last_device_connected_state_(false) {
     CHECK(adapter_);
     adapter_->AddObserver(this);
   }
@@ -73,18 +75,37 @@ class TestObserver final : public bluetooth::Adapter::Observer {
   bluetooth::AdapterState prev_state() const { return prev_state_; }
   bluetooth::AdapterState cur_state() const { return cur_state_; }
 
+  std::string last_connection_state_address() const {
+    return last_connection_state_address_;
+  }
+
+  bool last_device_connected_state() const {
+    return last_device_connected_state_;
+  }
+
   // bluetooth::Adapter::Observer override:
   void OnAdapterStateChanged(bluetooth::Adapter* adapter,
                              bluetooth::AdapterState prev_state,
-                             bluetooth::AdapterState new_state) {
+                             bluetooth::AdapterState new_state) override {
     ASSERT_EQ(adapter_, adapter);
     prev_state_ = prev_state;
     cur_state_ = new_state;
   }
 
+  void OnDeviceConnectionStateChanged(
+      Adapter* adapter,
+      const std::string& device_address,
+      bool connected) override {
+    ASSERT_EQ(adapter_, adapter);
+    last_connection_state_address_ = device_address;
+    last_device_connected_state_ = connected;
+  }
+
  private:
   bluetooth::Adapter* adapter_;
   bluetooth::AdapterState prev_state_, cur_state_;
+  std::string last_connection_state_address_;
+  bool last_device_connected_state_;
 
   DISALLOW_COPY_AND_ASSIGN(TestObserver);
 };
@@ -232,5 +253,36 @@ TEST_F(AdapterTest, IsMultiAdvertisementSupported) {
   EXPECT_FALSE(adapter_->IsMultiAdvertisementSupported());
 }
 
+TEST_F(AdapterTest, IsDeviceConnected) {
+  const char kDeviceAddr[] = "12:34:56:78:9A:BC";
+  TestObserver observer(adapter_.get());
+
+  EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+
+  bt_bdaddr_t hal_addr;
+  ASSERT_TRUE(util::BdAddrFromString(kDeviceAddr, &hal_addr));
+
+  // status != BT_STATUS_SUCCESS should be ignored
+  fake_hal_iface_->NotifyAclStateChangedCallback(
+      BT_STATUS_FAIL, hal_addr, BT_ACL_STATE_CONNECTED);
+  EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+  EXPECT_TRUE(observer.last_connection_state_address().empty());
+  EXPECT_FALSE(observer.last_device_connected_state());
+
+  // Connected
+  fake_hal_iface_->NotifyAclStateChangedCallback(
+      BT_STATUS_SUCCESS, hal_addr, BT_ACL_STATE_CONNECTED);
+  EXPECT_TRUE(adapter_->IsDeviceConnected(kDeviceAddr));
+  EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+  EXPECT_TRUE(observer.last_device_connected_state());
+
+  // Disconnected
+  fake_hal_iface_->NotifyAclStateChangedCallback(
+      BT_STATUS_SUCCESS, hal_addr, BT_ACL_STATE_DISCONNECTED);
+  EXPECT_FALSE(adapter_->IsDeviceConnected(kDeviceAddr));
+  EXPECT_EQ(kDeviceAddr, observer.last_connection_state_address());
+  EXPECT_FALSE(observer.last_device_connected_state());
+}
+
 }  // namespace
 }  // namespace bluetooth