Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90315261 authored by Krzysztof Kopyściński's avatar Krzysztof Kopyściński Committed by Krzysztof Kopyscinski (xWF)
Browse files

has_client.cc: cleanup device when GATT operations may be pending

We should clear device that is getting disconnected after it was already
disconnected, otherwise it's GATT queue may have pending elements that
will belong to next device that gets same connection ID.

Bug: 361721967
Test: atest --host --no-bazel-mode bluetooth_has_test
Change-Id: Iea06ff952e78534cf672fc1296f220e52e89ac84
parent b3c46bf0
Loading
Loading
Loading
Loading
+25 −8
Original line number Diff line number Diff line
@@ -429,7 +429,7 @@ public:
      ClearDeviceInformationAndStartSearch(device);
    } else {
      log::error("Devices {}: Control point not usable. Disconnecting!", device->addr);
      BTA_GATTC_Close(device->conn_id);
      CleanAndDisconnectByConnId(conn_id);
    }
  }

@@ -475,7 +475,7 @@ public:
      ClearDeviceInformationAndStartSearch(device);
    } else {
      log::error("Devices {}: Control point not usable. Disconnecting!", device->addr);
      BTA_GATTC_Close(device->conn_id);
      CleanAndDisconnectByConnId(conn_id);
    }
  }

@@ -1137,7 +1137,7 @@ private:
      /* Both of these CCC are mandatory */
      if (enabling_ntf && (status != GATT_SUCCESS)) {
        log::error("Failed to register for notifications on handle=0x{:x}", handle);
        BTA_GATTC_Close(conn_id);
        CleanAndDisconnectByConnId(conn_id);
        return;
      }
    }
@@ -1189,20 +1189,22 @@ private:
      return;
    }

    tCONN_ID conn_id = device->conn_id;

    if (status != GATT_SUCCESS) {
      if (status == GATT_DATABASE_OUT_OF_SYNC) {
        log::info("Database out of sync for {}", device->addr);
        ClearDeviceInformationAndStartSearch(device);
      } else {
        log::error("Could not read characteristic at handle=0x{:04x}", handle);
        BTA_GATTC_Close(device->conn_id);
        CleanAndDisconnectByConnId(conn_id);
      }
      return;
    }

    if (len != 1) {
      log::error("Invalid features value length={} at handle=0x{:x}", len, handle);
      BTA_GATTC_Close(device->conn_id);
      CleanAndDisconnectByConnId(conn_id);
      return;
    }

@@ -1565,9 +1567,11 @@ private:

  void OnHasCtpValueNotification(HasDevice* device, uint16_t len, const uint8_t* value) {
    auto ntf_opt = HasCtpNtf::FromCharacteristicValue(len, value);
    tCONN_ID conn_id = device->conn_id;

    if (!ntf_opt.has_value()) {
      log::error("Unhandled notification for device: {}", *device);
      BTA_GATTC_Close(device->conn_id);
      CleanAndDisconnectByConnId(conn_id);
      return;
    }

@@ -1591,19 +1595,22 @@ private:
      return;
    }

    tCONN_ID conn_id = device->conn_id;

    if (status != GATT_SUCCESS) {
      if (status == GATT_DATABASE_OUT_OF_SYNC) {
        log::info("Database out of sync for {}", device->addr);
        ClearDeviceInformationAndStartSearch(device);
      } else {
        log::error("Could not read characteristic at handle=0x{:04x}", handle);
        BTA_GATTC_Close(device->conn_id);
        CleanAndDisconnectByConnId(conn_id);
        return;
      }
    }

    if (len != 1) {
      log::error("Invalid preset value length={} at handle=0x{:x}", len, handle);
      BTA_GATTC_Close(device->conn_id);
      CleanAndDisconnectByConnId(conn_id);
      return;
    }

@@ -1717,6 +1724,16 @@ private:
    device.ConnectionCleanUp();
  }

  void CleanAndDisconnectByConnId(tCONN_ID conn_id) {
    auto device_iter =
            std::find_if(devices_.begin(), devices_.end(), HasDevice::MatchConnId(conn_id));
    if (device_iter != devices_.end()) {
      DoDisconnectCleanUp(*device_iter);
      devices_.erase(device_iter);
    }
    BTA_GATTC_Close(conn_id);
  }

  /* These below are all GATT service discovery, validation, cache & storage */
  bool CacheAttributeHandles(const gatt::Service& service, HasDevice* device) {
    log::debug("device={}", device->addr);
+35 −0
Original line number Diff line number Diff line
@@ -1602,6 +1602,41 @@ TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset_ntf) {
  TestConnect(test_address);
}

TEST_F(HasClientTest, test_cp_not_usable_read_all_presets) {
  osi_property_set_bool("persist.bluetooth.has.always_use_preset_cache", false);

  const RawAddress test_address = GetTestAddress(1);
  std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
          HasPreset(1, HasPreset::kPropertyAvailable, "Universal"),
          HasPreset(2, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable, "Preset2"),
  }};

  SetSampleDatabaseHasPresetsNtf(test_address,
                                 bluetooth::has::kFeatureBitHearingAidTypeBanded |
                                         bluetooth::has::kFeatureBitWritablePresets |
                                         bluetooth::has::kFeatureBitDynamicPresets,
                                 has_presets);

  ON_CALL(gatt_queue, ReadCharacteristic(_, HasDbBuilder::kActivePresetIndexValHdl, _, _))
          .WillByDefault(Invoke([&](uint16_t conn_id, uint16_t handle, GATT_READ_OP_CB cb,
                                    void* cb_data) -> void {
            std::vector<uint8_t> value;

            tGATT_STATUS status = GATT_ERROR;
            if (cb) {
              cb(conn_id, status, handle, value.size(), value.data(), cb_data);
            }
          }));

  EXPECT_CALL(*callbacks,
              OnDeviceAvailable(test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded |
                                                      bluetooth::has::kFeatureBitWritablePresets |
                                                      bluetooth::has::kFeatureBitDynamicPresets));
  EXPECT_CALL(gatt_queue, Clean(1)).Times(1);

  TestConnect(test_address);
}

TEST_F(HasClientTest, test_discovery_has_features_ntf) {
  const RawAddress test_address = GetTestAddress(1);
  auto test_conn_id = GetTestConnId(test_address);