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

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

csis: Add handling DATABASE OUT OF SYNC

Bug: 262309077
Test: atest BluetoothInstrumentationTests
Tag: #feature
Merged-In: I7eedc84c42203f8ddeab30b64fe773bf27a1eb4b
Change-Id: I7eedc84c42203f8ddeab30b64fe773bf27a1eb4b
(cherry picked from commit 6237e4c7)
parent c38ca682
Loading
Loading
Loading
Loading
+74 −31
Original line number Diff line number Diff line
@@ -338,11 +338,16 @@ class CsisClientImpl : public CsisClient {
      }

      /* In case of GATT ERROR */
      LOG(ERROR) << __func__ << " Incorrect write status "
                 << loghex((int)(status));
      LOG_ERROR("Incorrect write status=0x%02x", (int)(status));

      /* Unlock previous devices */
      HandleCsisLockProcedureError(csis_group, device);

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

@@ -839,6 +844,11 @@ class CsisClientImpl : public CsisClient {
      BtaGattQueue::Clean(conn_id);
      return;
    }

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

  void OnCsisNotification(uint16_t conn_id, uint16_t handle, uint16_t len,
@@ -955,13 +965,17 @@ class CsisClientImpl : public CsisClient {
      return;
    }

    DLOG(INFO) << __func__ << " " << device->addr
               << " status: " << loghex(+status);
    LOG_DEBUG("%s, status: 0x%02x", device->addr.ToString().c_str(), status);

    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;
    }

@@ -999,13 +1013,17 @@ class CsisClientImpl : public CsisClient {
      return;
    }

    LOG(INFO) << __func__ << " " << device->addr
              << " status: " << loghex(+status);
    LOG_INFO("%s, status 0x%02x", device->addr.ToString().c_str(), status);

    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;
    }

@@ -1034,13 +1052,18 @@ class CsisClientImpl : public CsisClient {
      return;
    }

    DLOG(INFO) << __func__ << " " << device->addr
               << " status: " << loghex(+status) << " rank:" << int(value[0]);
    LOG_DEBUG("%s, status: 0x%02x, rank: %d", device->addr.ToString().c_str(),
              status, value[0]);

    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;
    }

@@ -1333,17 +1356,21 @@ class CsisClientImpl : public CsisClient {
      return;
    }

    DLOG(INFO) << __func__ << " " << device->addr
               << " status: " << loghex(+status);
    LOG_DEBUG("%s, status: 0x%02x", device->addr.ToString().c_str(), status);

    if (status != GATT_SUCCESS) {
      /* TODO handle error codes:
       * kCsisErrorCodeLockAccessSirkRejected
       * kCsisErrorCodeLockOobSirkOnly
       */
      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;
    }

@@ -1438,9 +1465,7 @@ class CsisClientImpl : public CsisClient {
      CsisActiveDiscovery(csis_group);
  }

  void DoDisconnectCleanUp(std::shared_ptr<CsisDevice> device) {
    DLOG(INFO) << __func__ << ": device=" << device->addr;

  void DeregisterNotifications(std::shared_ptr<CsisDevice> device) {
    device->ForEachCsisInstance(
        [&](const std::shared_ptr<CsisInstance>& csis_inst) {
          DisableGattNotification(device->conn_id, device->addr,
@@ -1450,6 +1475,12 @@ class CsisClientImpl : public CsisClient {
          DisableGattNotification(device->conn_id, device->addr,
                                  csis_inst->svc_data.size_handle.val_hdl);
        });
  }

  void DoDisconnectCleanUp(std::shared_ptr<CsisDevice> device) {
    LOG_INFO("%s", device->addr.ToString().c_str());

    DeregisterNotifications(device);

    if (device->IsConnected()) {
      BtaGattQueue::Clean(device->conn_id);
@@ -1845,19 +1876,31 @@ class CsisClientImpl : public CsisClient {
    }
  }

  void OnGattServiceChangeEvent(const RawAddress& address) {
    auto device = FindDeviceByAddress(address);
    if (!device) {
      LOG(WARNING) << "Skipping unknown device" << address;
  void ClearDeviceInformationAndStartSearch(
      std::shared_ptr<CsisDevice> device) {
    LOG_INFO("%s ", device->addr.ToString().c_str());
    if (device->is_gatt_service_valid == false) {
      LOG_DEBUG("Device database already invalidated.");
      return;
    }

    DLOG(INFO) << __func__ << ": address=" << address;

    /* Invalidate service discovery results */
    BtaGattQueue::Clean(device->conn_id);
    device->first_connection = true;
    DeregisterNotifications(device);
    device->ClearSvcData();
    BTA_GATTC_ServiceSearchRequest(device->conn_id, &kCsisServiceUuid);
  }

  void OnGattServiceChangeEvent(const RawAddress& address) {
    auto device = FindDeviceByAddress(address);
    if (!device) {
      LOG(WARNING) << "Skipping unknown device" << address;
      return;
    }

    LOG_INFO("%s", address.ToString().c_str());
    ClearDeviceInformationAndStartSearch(device);
  }

  void OnGattServiceDiscoveryDoneEvent(const RawAddress& address) {
+36 −0
Original line number Diff line number Diff line
@@ -1124,6 +1124,42 @@ TEST_F(CsisClientTest, test_storage_content) {
  TestAppUnregister();
}

TEST_F(CsisClientTest, test_database_out_of_sync) {
  auto test_address = GetTestAddress(0);
  auto conn_id = 1;

  TestAppRegister();
  SetSampleDatabaseCsis(conn_id, 1);
  TestConnect(test_address);
  InjectConnectedEvent(test_address, conn_id);
  GetSearchCompleteEvent(conn_id);
  ASSERT_EQ(1, CsisClient::Get()->GetGroupId(
                   test_address, bluetooth::Uuid::From16Bit(0x0000)));

  // Simulated database changed 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(_, _));
  CsisClient::Get()->LockGroup(
      1, true,
      base::BindOnce([](int group_id, bool locked, CsisGroupLockStatus status) {
        csis_lock_callback_mock->CsisGroupLockCb(group_id, locked, status);
      }));
  TestAppUnregister();
}

}  // namespace
}  // namespace internal
}  // namespace csis