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

Commit 0f39397d authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

has_client: Always write CCC values

We do not trust devices and always write CCC.
It will also help with PTS

Bug: 238171211
Test: atest BluetoothInstrumentationTests
Test: PTS
Tag: #feature
Merged-In: Ifb354d772fcdf6963f24e962e8b2864902bfb8f2
Change-Id: Ifb354d772fcdf6963f24e962e8b2864902bfb8f2
(cherry picked from commit 6aa1e219)
parent 7976c59b
Loading
Loading
Loading
Loading
+30 −25
Original line number Diff line number Diff line
@@ -891,6 +891,29 @@ class HasClientImpl : public HasClient {
  }

 private:
  void WriteAllNeededCcc(const HasDevice& device) {
    if (device.conn_id == GATT_INVALID_CONN_ID) {
      LOG_ERROR("Device %s is not connected", device.addr.ToString().c_str());
      return;
    }

    /* Write CCC values even remote should have it */
    LOG_INFO("Subscribing for notification/indications");
    if (device.SupportsFeaturesNotification()) {
      SubscribeForNotifications(device.conn_id, device.addr,
                                device.features_handle,
                                device.features_ccc_handle);
    }

    if (device.SupportsPresets()) {
      SubscribeForNotifications(device.conn_id, device.addr, device.cp_handle,
                                device.cp_ccc_handle, device.cp_ccc_val);
      SubscribeForNotifications(device.conn_id, device.addr,
                                device.active_preset_handle,
                                device.active_preset_ccc_handle);
    }
  }

  void OnEncrypted(HasDevice& device) {
    DLOG(INFO) << __func__ << ": " << device.addr;

@@ -901,7 +924,7 @@ class HasClientImpl : public HasClient {
                               device.GetAllPresetInfo());
      callbacks_->OnActivePresetSelected(device.addr,
                                         device.currently_active_preset);

      WriteAllNeededCcc(device);
    } else {
      BTA_GATTC_ServiceSearchRequest(device.conn_id,
                                     &kUuidHearingAccessService);
@@ -1584,30 +1607,6 @@ class HasClientImpl : public HasClient {

    device->currently_active_preset = active_preset;

    /* Register for optional features notifications */
    if (device->features_ccc_handle != GAP_INVALID_HANDLE) {
      tGATT_STATUS register_status = BTA_GATTC_RegisterForNotifications(
          gatt_if_, device->addr, device->features_handle);
      DLOG(INFO) << __func__ << " Registering for notifications, status="
                 << loghex(+register_status);
    }

    /* Register for presets control point notifications */
    if (device->cp_ccc_handle != GAP_INVALID_HANDLE) {
      tGATT_STATUS register_status = BTA_GATTC_RegisterForNotifications(
          gatt_if_, device->addr, device->cp_handle);
      DLOG(INFO) << __func__ << " Registering for notifications, status="
                 << loghex(+register_status);
    }

    /* Register for active presets notifications if presets exist */
    if (device->active_preset_ccc_handle != GAP_INVALID_HANDLE) {
      tGATT_STATUS register_status = BTA_GATTC_RegisterForNotifications(
          gatt_if_, device->addr, device->active_preset_handle);
      DLOG(INFO) << __func__ << " Registering for notifications, status="
                 << loghex(+register_status);
    }

    /* Update features and refresh opcode support map */
    uint8_t val;
    if (btif_storage_get_leaudio_has_features(device->addr, val))
@@ -1622,6 +1621,12 @@ class HasClientImpl : public HasClient {
                             device->GetAllPresetInfo());
    callbacks_->OnActivePresetSelected(device->addr,
                                       device->currently_active_preset);
    if (device->conn_id == GATT_INVALID_CONN_ID) return true;

    /* Be mistrustful here: write CCC values even remote should have it */
    LOG_INFO("Subscribing for notification/indications");
    WriteAllNeededCcc(*device);

    return true;
  }

+54 −2
Original line number Diff line number Diff line
@@ -1341,7 +1341,7 @@ TEST_F(HasClientTest, test_reconnect_after_encryption_failed_from_storage) {
  InjectConnectedEvent(test_address, GetTestConnId(test_address));
}

TEST_F(HasClientTest, test_load_from_storage) {
TEST_F(HasClientTest, test_load_from_storage_and_connect) {
  const RawAddress test_address = GetTestAddress(1);
  SetSampleDatabaseHasPresetsNtf(test_address, kFeatureBitDynamicPresets, {{}});
  SetEncryptionResult(test_address, true);
@@ -1392,7 +1392,7 @@ TEST_F(HasClientTest, test_load_from_storage) {

  /* Expect no read or write operations when loading from storage */
  EXPECT_CALL(gatt_queue, ReadCharacteristic(1, _, _, _)).Times(0);
  EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(0);
  EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(3);

  TestAddFromStorage(test_address,
                     kFeatureBitWritablePresets |
@@ -1411,6 +1411,58 @@ TEST_F(HasClientTest, test_load_from_storage) {
  }
}

TEST_F(HasClientTest, test_load_from_storage) {
  const RawAddress test_address = GetTestAddress(1);
  SetSampleDatabaseHasPresetsNtf(test_address, kFeatureBitDynamicPresets, {{}});
  SetEncryptionResult(test_address, true);

  std::set<HasPreset, HasPreset::ComparatorDesc> has_presets = {{
      HasPreset(5, HasPreset::kPropertyAvailable | HasPreset::kPropertyWritable,
                "YourWritablePreset5"),
      HasPreset(55, HasPreset::kPropertyAvailable, "YourPreset55"),
  }};

  /* Load persistent storage data */
  ON_CALL(btif_storage_interface_, GetLeaudioHasPresets(test_address, _, _))
      .WillByDefault([&has_presets](const RawAddress& address,
                                    std::vector<uint8_t>& presets_bin,
                                    uint8_t& active_preset) {
        /* Generate presets binary to be used instead the attribute values */
        HasDevice device(address, 0);
        device.has_presets = has_presets;
        active_preset = 55;

        if (device.SerializePresets(presets_bin)) return true;

        return false;
      });

  EXPECT_CALL(gatt_interface, RegisterForNotifications(gatt_if, _, _))
      .Times(0);  // features

  EXPECT_CALL(*callbacks,
              OnDeviceAvailable(test_address,
                                (kFeatureBitWritablePresets |
                                 kFeatureBitPresetSynchronizationSupported |
                                 kFeatureBitHearingAidTypeBanded)));

  std::vector<PresetInfo> loaded_preset_details;
  EXPECT_CALL(*callbacks,
              OnPresetInfo(std::variant<RawAddress, int>(test_address),
                           PresetInfoReason::ALL_PRESET_INFO, _))
      .Times(0);

  /* Expect no read or write operations when loading from storage */
  EXPECT_CALL(gatt_queue, ReadCharacteristic(1, _, _, _)).Times(0);
  EXPECT_CALL(gatt_queue, WriteDescriptor(1, _, _, _, _, _)).Times(0);

  TestAddFromStorage(test_address,
                     kFeatureBitWritablePresets |
                         kFeatureBitPresetSynchronizationSupported |
                         kFeatureBitHearingAidTypeBanded,
                     false);
}

TEST_F(HasClientTest, test_write_to_storage) {
  const RawAddress test_address = GetTestAddress(1);