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

Commit 3de584ff authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

has: Add support for DATABASE_OUT_OF_SYNC

Bug: 262309077
Tag: #feature
Test: atest BluetoothInstrumentationTests
Merged-In: Ieaa26a0b81549ab0136774dfc0935563e081f0a5
Change-Id: Ieaa26a0b81549ab0136774dfc0935563e081f0a5
(cherry picked from commit d4956cca)
parent fd2f985c
Loading
Loading
Loading
Loading
+81 −24
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ void btif_storage_set_leaudio_has_features(const RawAddress& address,
                                           uint8_t features);
void btif_storage_set_leaudio_has_active_preset(const RawAddress& address,
                                                uint8_t active_preset);
void btif_storage_remove_leaudio_has(const RawAddress& address);

extern bool gatt_profile_get_eatt_support(const RawAddress& remote_bda);

@@ -309,6 +310,11 @@ class HasClientImpl : public HasClient {
    auto op = op_opt.value();
    callbacks_->OnActivePresetSelectError(op.addr_or_group,
                                          GattStatus2SvcErrorCode(status));

    if (status == GATT_DATABASE_OUT_OF_SYNC) {
      LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
      ClearDeviceInformationAndStartSearch(device);
    }
  }

  void OnHasPresetNameSetStatus(uint16_t conn_id, tGATT_STATUS status,
@@ -339,6 +345,10 @@ class HasClientImpl : public HasClient {
    auto op = op_opt.value();
    callbacks_->OnSetPresetNameError(device->addr, op.index,
                                     GattStatus2SvcErrorCode(status));
    if (status == GATT_DATABASE_OUT_OF_SYNC) {
      LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
      ClearDeviceInformationAndStartSearch(device);
    }
  }

  void OnHasPresetNameGetStatus(uint16_t conn_id, tGATT_STATUS status,
@@ -367,9 +377,14 @@ class HasClientImpl : public HasClient {
    callbacks_->OnPresetInfoError(device->addr, op.index,
                                  GattStatus2SvcErrorCode(status));

    if (status == GATT_DATABASE_OUT_OF_SYNC) {
      LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
      ClearDeviceInformationAndStartSearch(device);
    } else {
      LOG_ERROR("Devices %s: Control point not usable. Disconnecting!",
                device->addr.ToString().c_str());
    BTA_GATTC_Close(conn_id);
      BTA_GATTC_Close(device->conn_id);
    }
  }

  void OnHasPresetIndexOperation(uint16_t conn_id, tGATT_STATUS status,
@@ -409,9 +424,15 @@ class HasClientImpl : public HasClient {
      callbacks_->OnActivePresetSelectError(op.addr_or_group,
                                            GattStatus2SvcErrorCode(status));
    }

    if (status == GATT_DATABASE_OUT_OF_SYNC) {
      LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
      ClearDeviceInformationAndStartSearch(device);
    } else {
      LOG_ERROR("Devices %s: Control point not usable. Disconnecting!",
                device->addr.ToString().c_str());
    BTA_GATTC_Close(conn_id);
      BTA_GATTC_Close(device->conn_id);
    }
  }

  void CpReadAllPresetsOperation(HasCtpOp operation) {
@@ -988,6 +1009,12 @@ class HasClientImpl : public HasClient {
      return;
    }

    if (status == GATT_DATABASE_OUT_OF_SYNC) {
      LOG_INFO("Database out of sync for %s", device->addr.ToString().c_str());
      ClearDeviceInformationAndStartSearch(device);
      return;
    }

    HasGattOpContext context(user_data);
    bool enabling_ntf = context.context_flags &
                        HasGattOpContext::kContextFlagsEnableNotification;
@@ -1058,9 +1085,14 @@ class HasClientImpl : public HasClient {
    }

    if (status != GATT_SUCCESS) {
      LOG(ERROR) << __func__ << ": Could not read characteristic at handle="
                 << loghex(handle);
      if (status == GATT_DATABASE_OUT_OF_SYNC) {
        LOG_INFO("Database out of sync for %s",
                 device->addr.ToString().c_str());
        ClearDeviceInformationAndStartSearch(device);
      } else {
        LOG_ERROR("Could not read characteristic at handle=0x%04x", handle);
        BTA_GATTC_Close(device->conn_id);
      }
      return;
    }

@@ -1434,10 +1466,14 @@ class HasClientImpl : public HasClient {
    }

    if (status != GATT_SUCCESS) {
      LOG(ERROR) << __func__ << ": Could not read characteristic at handle="
                 << loghex(handle);
      if (status == GATT_DATABASE_OUT_OF_SYNC) {
        LOG_INFO("Database out of sync for %s",
                 device->addr.ToString().c_str());
        ClearDeviceInformationAndStartSearch(device);
      } else {
        LOG_ERROR("Could not read characteristic at handle=0x%04x", handle);
        BTA_GATTC_Close(device->conn_id);
      return;
      }
    }

    if (len != 1) {
@@ -1507,11 +1543,7 @@ class HasClientImpl : public HasClient {
    }
  }

  /* Cleans up after the device disconnection */
  void DoDisconnectCleanUp(HasDevice& device,
                           bool invalidate_gatt_service = true) {
    DLOG(INFO) << __func__ << ": device=" << device.addr;

  void DeregisterNotifications(HasDevice& device) {
    /* Deregister from optional features notifications */
    if (device.features_ccc_handle != GAP_INVALID_HANDLE) {
      BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
@@ -1529,6 +1561,14 @@ class HasClientImpl : public HasClient {
      BTA_GATTC_DeregisterForNotifications(gatt_if_, device.addr,
                                           device.cp_handle);
    }
  }

  /* Cleans up after the device disconnection */
  void DoDisconnectCleanUp(HasDevice& device,
                           bool invalidate_gatt_service = true) {
    LOG_DEBUG(": device=%s", device.addr.ToString().c_str());

    DeregisterNotifications(device);

    if (device.conn_id != GATT_INVALID_CONN_ID) {
      BtaGattQueue::Clean(device.conn_id);
@@ -1940,19 +1980,36 @@ class HasClientImpl : public HasClient {
    }
  }

  void OnGattServiceChangeEvent(const RawAddress& address) {
    auto device = std::find_if(devices_.begin(), devices_.end(),
                               HasDevice::MatchAddress(address));
    if (device == devices_.end()) {
      LOG(WARNING) << "Skipping unknown device" << address;
  void ClearDeviceInformationAndStartSearch(HasDevice* device) {
    if (!device) {
      LOG_ERROR("Device is null");
      return;
    }

    DLOG(INFO) << __func__ << ": address=" << address;
    LOG_INFO("%s", device->addr.ToString().c_str());

    if (!device->isGattServiceValid()) {
      LOG_INFO("Service already invalidated");
      return;
    }

    /* Invalidate service discovery results */
    DeregisterNotifications(*device);
    BtaGattQueue::Clean(device->conn_id);
    device->ClearSvcData();
    btif_storage_remove_leaudio_has(device->addr);
    BTA_GATTC_ServiceSearchRequest(device->conn_id, &kUuidHearingAccessService);
  }

  void OnGattServiceChangeEvent(const RawAddress& address) {
    auto device = std::find_if(devices_.begin(), devices_.end(),
                               HasDevice::MatchAddress(address));
    if (device == devices_.end()) {
      LOG(WARNING) << "Skipping unknown device" << address;
      return;
    }
    LOG_INFO("%s", address.ToString().c_str());
    ClearDeviceInformationAndStartSearch(&(*device));
  }

  void OnGattServiceDiscoveryDoneEvent(const RawAddress& address) {
+43 −0
Original line number Diff line number Diff line
@@ -2926,6 +2926,49 @@ TEST_F(HasClientTest, test_dumpsys) {
  ASSERT_TRUE(SimpleJsonValidator(sv[1], &dumpsys_byte_cnt));
}

TEST_F(HasClientTest, test_connect_database_out_of_sync) {
  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);

  EXPECT_CALL(*callbacks, OnDeviceAvailable(
                              test_address,
                              bluetooth::has::kFeatureBitHearingAidTypeBanded |
                                  bluetooth::has::kFeatureBitWritablePresets |
                                  bluetooth::has::kFeatureBitDynamicPresets));
  EXPECT_CALL(*callbacks,
              OnConnectionState(ConnectionState::CONNECTED, test_address));
  TestConnect(test_address);

  ON_CALL(gatt_queue, WriteCharacteristic(_, _, _, _, _, _))
      .WillByDefault(
          Invoke([this](uint16_t conn_id, uint16_t handle,
                        std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
                        GATT_WRITE_OP_CB cb, void* cb_data) {
            auto* svc = gatt::FindService(services_map[conn_id], handle);
            if (svc == nullptr) return;

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

  ON_CALL(gatt_interface, ServiceSearchRequest(_, _)).WillByDefault(Return());
  EXPECT_CALL(gatt_interface, ServiceSearchRequest(_, _));
  HasClient::Get()->GetPresetInfo(test_address, 1);
}

class HasTypesTest : public ::testing::Test {
 protected:
  void SetUp(void) override { mock_function_count_map.clear(); }
+5 −0
Original line number Diff line number Diff line
@@ -111,3 +111,8 @@ void btif_storage_set_leaudio_has_active_preset(const RawAddress& address,
  LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!";
  btif_storage_interface->SetLeaudioHasActivePreset(address, active_preset);
}

void btif_storage_remove_leaudio_has(const RawAddress& address) {
  LOG_ASSERT(btif_storage_interface) << "Mock storage module not set!";
  btif_storage_interface->RemoveLeaudioHas(address);
}
 No newline at end of file
+3 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ class BtifStorageInterface {
  virtual bool GetLeaudioHasPresets(const RawAddress& address,
                                    std::vector<uint8_t>& presets_bin,
                                    uint8_t& active_preset) = 0;
  virtual void RemoveLeaudioHas(const RawAddress& address) = 0;

  virtual ~BtifStorageInterface() = default;
};
@@ -88,6 +89,8 @@ class MockBtifStorageInterface : public BtifStorageInterface {
              (const RawAddress& address, uint8_t features), (override));
  MOCK_METHOD((void), SetLeaudioHasActivePreset,
              (const RawAddress& address, uint8_t active_preset), (override));
  MOCK_METHOD((void), RemoveLeaudioHas, (const RawAddress& address),
              (override));
};

/**