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

Commit fd2f985c authored by Łukasz Rymanowski's avatar Łukasz Rymanowski
Browse files

vc: Add handling DATABASE_OUT_OF_SYNC

Bug: 262309077
Tag: #feature
Test: atest BluetoothInstrumentationTests
Merged-In: I177268b2cbc14c14332f54962479dc24ba3cba1c
Change-Id: I177268b2cbc14c14332f54962479dc24ba3cba1c
(cherry picked from commit 0abd8868)
parent 874777f6
Loading
Loading
Loading
Loading
+17 −16
Original line number Original line Diff line number Diff line
@@ -29,17 +29,12 @@


using namespace bluetooth::vc::internal;
using namespace bluetooth::vc::internal;


void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) {
void VolumeControlDevice::DeregisterNotifications(tGATT_IF gatt_if) {
  LOG(INFO) << __func__ << ": " << this->ToString();

  if (IsConnected()) {
  if (volume_state_handle != 0)
  if (volume_state_handle != 0)
      BTA_GATTC_DeregisterForNotifications(gatt_if, address,
    BTA_GATTC_DeregisterForNotifications(gatt_if, address, volume_state_handle);
                                           volume_state_handle);


  if (volume_flags_handle != 0)
  if (volume_flags_handle != 0)
      BTA_GATTC_DeregisterForNotifications(gatt_if, address,
    BTA_GATTC_DeregisterForNotifications(gatt_if, address, volume_flags_handle);
                                           volume_flags_handle);


  for (const VolumeOffset& of : audio_offsets.volume_offsets) {
  for (const VolumeOffset& of : audio_offsets.volume_offsets) {
    BTA_GATTC_DeregisterForNotifications(gatt_if, address,
    BTA_GATTC_DeregisterForNotifications(gatt_if, address,
@@ -48,7 +43,13 @@ void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) {
                                         of.audio_location_handle);
                                         of.audio_location_handle);
    BTA_GATTC_DeregisterForNotifications(gatt_if, address, of.state_handle);
    BTA_GATTC_DeregisterForNotifications(gatt_if, address, of.state_handle);
  }
  }
}


void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) {
  LOG(INFO) << __func__ << ": " << this->ToString();

  if (IsConnected()) {
    DeregisterNotifications(gatt_if);
    BtaGattQueue::Clean(connection_id);
    BtaGattQueue::Clean(connection_id);
    BTA_GATTC_Close(connection_id);
    BTA_GATTC_Close(connection_id);
    connection_id = GATT_INVALID_CONN_ID;
    connection_id = GATT_INVALID_CONN_ID;
+2 −0
Original line number Original line Diff line number Diff line
@@ -109,6 +109,8 @@ class VolumeControlDevice {


  void Disconnect(tGATT_IF gatt_if);
  void Disconnect(tGATT_IF gatt_if);


  void DeregisterNotifications(tGATT_IF gatt_if);

  bool UpdateHandles(void);
  bool UpdateHandles(void);


  void ResetHandles(void);
  void ResetHandles(void);
+46 −9
Original line number Original line Diff line number Diff line
@@ -182,6 +182,29 @@ class VolumeControlImpl : public VolumeControl {
    }
    }
  }
  }


  void ClearDeviceInformationAndStartSearch(VolumeControlDevice* device) {
    if (!device) {
      LOG_ERROR("Device is null");
      return;
    }

    LOG_INFO(": address=%s", device->address.ToString().c_str());
    if (device->service_changed_rcvd) {
      LOG_INFO("Device already is waiting for new services");
      return;
    }

    std::vector<RawAddress> devices = {device->address};
    device->DeregisterNotifications(gatt_if_);

    RemovePendingVolumeControlOperations(devices,
                                         bluetooth::groups::kGroupUnknown);
    device->first_connection = true;
    device->service_changed_rcvd = true;
    BtaGattQueue::Clean(device->connection_id);
    BTA_GATTC_ServiceSearchRequest(device->connection_id, &kVolumeControlUuid);
  }

  void OnServiceChangeEvent(const RawAddress& address) {
  void OnServiceChangeEvent(const RawAddress& address) {
    VolumeControlDevice* device =
    VolumeControlDevice* device =
        volume_control_devices_.FindByAddress(address);
        volume_control_devices_.FindByAddress(address);
@@ -189,10 +212,8 @@ class VolumeControlImpl : public VolumeControl {
      LOG(ERROR) << __func__ << "Skipping unknown device " << address;
      LOG(ERROR) << __func__ << "Skipping unknown device " << address;
      return;
      return;
    }
    }
    LOG(INFO) << __func__ << ": address=" << address;

    device->first_connection = true;
    ClearDeviceInformationAndStartSearch(device);
    device->service_changed_rcvd = true;
    BtaGattQueue::Clean(device->connection_id);
  }
  }


  void OnServiceDiscDoneEvent(const RawAddress& address) {
  void OnServiceDiscDoneEvent(const RawAddress& address) {
@@ -249,7 +270,12 @@ class VolumeControlImpl : public VolumeControl {
    }
    }


    if (status != GATT_SUCCESS) {
    if (status != GATT_SUCCESS) {
      LOG(INFO) << __func__ << ": status=" << static_cast<int>(status);
      LOG_INFO(": status=0x%02x", static_cast<int>(status));
      if (status == GATT_DATABASE_OUT_OF_SYNC) {
        LOG_INFO("Database out of sync for %s",
                 device->address.ToString().c_str());
        ClearDeviceInformationAndStartSearch(device);
      }
      return;
      return;
    }
    }


@@ -547,10 +573,15 @@ class VolumeControlImpl : public VolumeControl {
    }
    }


    if (status != GATT_SUCCESS) {
    if (status != GATT_SUCCESS) {
      LOG(ERROR) << __func__
      if (status == GATT_DATABASE_OUT_OF_SYNC) {
                 << "Failed to register for notification: " << loghex(handle)
        LOG_INFO("Database out of sync for %s, conn_id: 0x%04x",
                 << " status: " << status;
                 device->address.ToString().c_str(), connection_id);
        ClearDeviceInformationAndStartSearch(device);
      } else {
        LOG_ERROR("Failed to register for notification: 0x%04x, status 0x%02x",
                  handle, status);
        device_cleanup_helper(device, true);
        device_cleanup_helper(device, true);
      }
      return;
      return;
    }
    }


@@ -683,6 +714,12 @@ class VolumeControlImpl : public VolumeControl {


    /* In case of error, remove device from the tracking operation list */
    /* In case of error, remove device from the tracking operation list */
    RemoveDeviceFromOperationList(device->address, PTR_TO_INT(data));
    RemoveDeviceFromOperationList(device->address, PTR_TO_INT(data));

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


  static void operation_callback(void* data) {
  static void operation_callback(void* data) {
+40 −0
Original line number Original line Diff line number Diff line
@@ -754,6 +754,46 @@ TEST_F(VolumeControlTest, test_discovery_vocs_broken) {
  TestAppUnregister();
  TestAppUnregister();
}
}


TEST_F(VolumeControlTest, test_read_vcs_database_out_of_sync) {
  const RawAddress test_address = GetTestAddress(0);
  EXPECT_CALL(*callbacks, OnVolumeStateChanged(test_address, _, _, false));
  std::vector<uint16_t> handles({0x0021});
  uint16_t conn_id = 1;

  SetSampleDatabase(conn_id);
  TestAppRegister();
  TestConnect(test_address);
  GetConnectedEvent(test_address, conn_id);

  EXPECT_CALL(gatt_queue, ReadCharacteristic(conn_id, _, _, _))
      .WillRepeatedly(DoDefault());
  for (auto const& handle : handles) {
    EXPECT_CALL(gatt_queue, ReadCharacteristic(conn_id, handle, _, _))
        .WillOnce(DoDefault());
  }
  GetSearchCompleteEvent(conn_id);

  /* Simulate database change on the remote side. */
  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(_, _));
  VolumeControl::Get()->SetVolume(test_address, 15);
  Mock::VerifyAndClearExpectations(&gatt_interface);
  TestAppUnregister();
}

class VolumeControlCallbackTest : public VolumeControlTest {
class VolumeControlCallbackTest : public VolumeControlTest {
 protected:
 protected:
  const RawAddress test_address = GetTestAddress(0);
  const RawAddress test_address = GetTestAddress(0);