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

Commit ac20377c authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "[LE Audio] Deregister notif when ccc fail of CSIS" into main

parents 0d8cdf10 6d8739c4
Loading
Loading
Loading
Loading
+52 −25
Original line number Diff line number Diff line
@@ -904,8 +904,6 @@ class CsisClientImpl : public CsisClient {

  void OnGattWriteCcc(uint16_t conn_id, tGATT_STATUS status, uint16_t handle,
                      void* user_data) {
    LOG(INFO) << __func__ << " handle=" << loghex(handle);

    auto device = FindDeviceByConnId(conn_id);
    if (device == nullptr) {
      LOG(INFO) << __func__ << " unknown conn_id=" << loghex(conn_id);
@@ -917,6 +915,29 @@ class CsisClientImpl : public CsisClient {
      LOG_INFO("Database out of sync for %s",
               ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      ClearDeviceInformationAndStartSearch(device);
      return;
    }

    if (status == GATT_SUCCESS) {
      LOG_INFO("Successfully registered on ccc: 0x%04x, device: %s", handle,
               ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      return;
    }

    LOG_ERROR(
        "Failed to register for indications: 0x%04x, device: %s, status: "
        "0x%02x",
        handle, ADDRESS_TO_LOGGABLE_CSTR(device->addr), status);

    auto val_handle = device->FindValueHandleByCccHandle(handle);
    if (!val_handle) {
      LOG_ERROR("Unknown ccc handle: 0x%04x, device: %s", handle,
                ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      return;
    }

    if (val_handle != GAP_INVALID_HANDLE) {
      BTA_GATTC_DeregisterForNotifications(gatt_if_, device->addr, val_handle);
    }
  }

@@ -1637,9 +1658,9 @@ class CsisClientImpl : public CsisClient {
                          const gatt::Service* service,
                          const bluetooth::Uuid& context_uuid,
                          bool is_last_instance) {
    DLOG(INFO) << __func__ << " service handle: " << loghex(service->handle)
               << " end handle: " << loghex(service->end_handle)
               << " uuid: " << context_uuid;
    LOG_DEBUG("service handle: 0x%04x, end handle: 0x%04x, uuid: %s",
              service->handle, service->end_handle,
              context_uuid.ToString().c_str());

    auto csis_inst = std::make_shared<CsisInstance>(
        (uint16_t)service->handle, (uint16_t)service->end_handle, context_uuid);
@@ -1649,6 +1670,8 @@ class CsisClientImpl : public CsisClient {
    if (group_id != bluetooth::groups::kGroupUnknown)
      csis_inst->SetGroupId(group_id);

    device->SetCsisInstance(csis_inst->svc_data.start_handle, csis_inst);

    /* Initially validate and store GATT service discovery data */
    for (const gatt::Characteristic& charac : service->characteristics) {
      if (charac.uuid == kCsisLockUuid) {
@@ -1656,8 +1679,8 @@ class CsisClientImpl : public CsisClient {
        uint16_t ccc_handle =
            FindCccHandle(device->conn_id, charac.value_handle);
        if (ccc_handle == GAP_INVALID_HANDLE) {
          DLOG(ERROR) << __func__
                      << ": no HAS Active Preset CCC descriptor found!";
          LOG_ERROR("no HAS Active Preset CCC descriptor found!");
          device->RemoveCsisInstance(group_id);
          return false;
        }
        csis_inst->svc_data.lock_handle.val_hdl = charac.value_handle;
@@ -1666,15 +1689,17 @@ class CsisClientImpl : public CsisClient {
        SubscribeForNotifications(device->conn_id, device->addr,
                                  charac.value_handle, ccc_handle);

        DLOG(INFO) << __func__ << " Lock UUID found handle: "
                   << loghex(csis_inst->svc_data.lock_handle.val_hdl)
                   << " ccc handle: "
                   << loghex(csis_inst->svc_data.lock_handle.ccc_hdl);
        LOG_DEBUG(
            "Lock UUID found handle: 0x%04x, ccc handle: 0x%04x, device: %s",
            csis_inst->svc_data.lock_handle.val_hdl,
            csis_inst->svc_data.lock_handle.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      } else if (charac.uuid == kCsisRankUuid) {
        csis_inst->svc_data.rank_handle = charac.value_handle;

        DLOG(INFO) << __func__ << " Rank UUID found handle: "
                   << loghex(csis_inst->svc_data.rank_handle);
        LOG_DEBUG("Rank UUID found handle: 0x%04x, device: %s",
                  csis_inst->svc_data.rank_handle,
                  ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      } else if (charac.uuid == kCsisSirkUuid) {
        /* Find the optional CCC descriptor */
        uint16_t ccc_handle =
@@ -1686,10 +1711,11 @@ class CsisClientImpl : public CsisClient {
          SubscribeForNotifications(device->conn_id, device->addr,
                                    charac.value_handle, ccc_handle);

        DLOG(INFO) << __func__ << " SIRK UUID found handle: "
                   << loghex(csis_inst->svc_data.sirk_handle.val_hdl)
                   << " ccc handle: "
                   << loghex(csis_inst->svc_data.sirk_handle.ccc_hdl);
        LOG_DEBUG(
            "SIRK UUID found handle: 0x%04x, ccc handle: 0x%04x, device: %s",
            csis_inst->svc_data.sirk_handle.val_hdl,
            csis_inst->svc_data.sirk_handle.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      } else if (charac.uuid == kCsisSizeUuid) {
        /* Find the optional CCC descriptor */
        uint16_t ccc_handle =
@@ -1701,10 +1727,11 @@ class CsisClientImpl : public CsisClient {
          SubscribeForNotifications(device->conn_id, device->addr,
                                    charac.value_handle, ccc_handle);

        DLOG(INFO) << __func__ << " Size UUID found handle: "
                   << loghex(csis_inst->svc_data.size_handle.val_hdl)
                   << " ccc handle: "
                   << loghex(csis_inst->svc_data.size_handle.ccc_hdl);
        LOG_DEBUG(
            "Size UUID found handle: 0x%04x, ccc handle: 0x%04x, device: %s",
            csis_inst->svc_data.size_handle.val_hdl,
            csis_inst->svc_data.size_handle.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(device->addr));
      }
    }

@@ -1714,9 +1741,9 @@ class CsisClientImpl : public CsisClient {
    if (csis_inst->svc_data.sirk_handle.val_hdl == GAP_INVALID_HANDLE) {
      /* We have some characteristics but all dependencies are not satisfied */
      LOG(ERROR) << __func__ << " Service has a broken structure.";
      device->RemoveCsisInstance(group_id);
      return false;
    }
    device->SetCsisInstance(csis_inst->svc_data.start_handle, csis_inst);

    bool notify_after_sirk_read = false;
    bool notify_after_lock_read = false;
@@ -2118,10 +2145,10 @@ class CsisClientImpl : public CsisClient {
    UINT16_TO_STREAM(value_ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION);
    BtaGattQueue::WriteDescriptor(
        conn_id, ccc_handle, std::move(value), GATT_WRITE,
        [](uint16_t conn_id, tGATT_STATUS status, uint16_t value_handle,
           uint16_t len, const uint8_t* value, void* user_data) {
        [](uint16_t conn_id, tGATT_STATUS status, uint16_t handle, uint16_t len,
           const uint8_t* value, void* user_data) {
          if (instance)
            instance->OnGattWriteCcc(conn_id, status, value_handle, user_data);
            instance->OnGattWriteCcc(conn_id, status, handle, user_data);
        },
        nullptr);
  }
+54 −0
Original line number Diff line number Diff line
@@ -534,6 +534,42 @@ class CsisClientTest : public ::testing::Test {
    TestAppUnregister();
  }

  void TestGattWriteCCC(uint16_t ccc_handle, GattStatus status,
                        int deregister_times) {
    SetSampleDatabaseCsis(1, 1);
    TestAppRegister();
    TestConnect(test_address);
    InjectConnectedEvent(test_address, 1);

    auto WriteDescriptorCbGenerator = [](tGATT_STATUS status,
                                         uint16_t ccc_handle) {
      return [status, ccc_handle](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) -> void {
        if (cb) {
          if (ccc_handle) {
            handle = ccc_handle;
          }
          cb(conn_id, status, handle, value.size(), value.data(), cb_data);
        }
      };
    };

    // sirk, size, lock
    EXPECT_CALL(gatt_queue, WriteDescriptor(_, _, _, _, _, _))
        .Times(3)
        .WillOnce(Invoke(WriteDescriptorCbGenerator(GATT_SUCCESS, 0)))
        .WillOnce(Invoke(WriteDescriptorCbGenerator(GATT_SUCCESS, 0)))
        .WillOnce(Invoke(WriteDescriptorCbGenerator(status, ccc_handle)));

    EXPECT_CALL(gatt_interface, DeregisterForNotifications(_, _, _))
        .Times(deregister_times);

    GetSearchCompleteEvent(1);
    Mock::VerifyAndClearExpectations(&gatt_interface);
  }

  void GetDisconnectedEvent(const RawAddress& address, uint16_t conn_id) {
    tBTA_GATTC_CLOSE event_data = {
        .conn_id = conn_id,
@@ -682,6 +718,24 @@ TEST_F(CsisClientTest, test_discovery_csis_broken) {
  TestAppUnregister();
}

TEST_F(CsisClientTest, test_ccc_reg_fail_handle_not_found) {
  // service handle range: 0x0001 ~ 0x0030
  uint16_t not_existed_ccc_handle = 0x0031;
  TestGattWriteCCC(not_existed_ccc_handle, GATT_INVALID_HANDLE, 0);
}

TEST_F(CsisClientTest, test_ccc_reg_fail_handle_found) {
  // kCsisLockUuid ccc handle
  uint16_t existed_ccc_hande = 0x0028;
  TestGattWriteCCC(existed_ccc_hande, GATT_INVALID_HANDLE, 1);
}

TEST_F(CsisClientTest, test_ccc_reg_fail_out_of_sync) {
  // kCsisLockUuid ccc handle
  uint16_t ccc_handle = 0x0028;
  TestGattWriteCCC(ccc_handle, GATT_DATABASE_OUT_OF_SYNC, 0);
}

class CsisClientCallbackTest : public CsisClientTest {
 protected:
  const RawAddress test_address = GetTestAddress(0);
+17 −0
Original line number Diff line number Diff line
@@ -220,6 +220,23 @@ class CsisDevice : public GattServiceDevice {
    csis_instances_.clear();
  }

  uint16_t FindValueHandleByCccHandle(uint16_t ccc_handle) {
    uint16_t val_handle = 0;
    for (const auto& [_, inst] : csis_instances_) {
      if (inst->svc_data.sirk_handle.ccc_hdl == ccc_handle) {
        val_handle = inst->svc_data.sirk_handle.val_hdl;
      } else if (inst->svc_data.lock_handle.ccc_hdl == ccc_handle) {
        val_handle = inst->svc_data.lock_handle.val_hdl;
      } else if (inst->svc_data.size_handle.ccc_hdl == ccc_handle) {
        val_handle = inst->svc_data.size_handle.val_hdl;
      }
      if (val_handle) {
        break;
      }
    }
    return val_handle;
  }

  std::shared_ptr<CsisInstance> GetCsisInstanceByOwningHandle(uint16_t handle) {
    uint16_t hdl = 0;
    for (const auto& [h, inst] : csis_instances_) {
+70 −44
Original line number Diff line number Diff line
@@ -2486,19 +2486,23 @@ class LeAudioClientImpl : public LeAudioClient {

    for (const gatt::Service& tmp : *services) {
      if (tmp.uuid == le_audio::uuid::kPublishedAudioCapabilityServiceUuid) {
        LOG(INFO) << "Found Audio Capability service, handle: "
                  << loghex(tmp.handle);
        LOG_INFO("Found Audio Capability service, handle: 0x%04x, device: %s",
                 tmp.handle, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
        pac_svc = &tmp;
      } else if (tmp.uuid == le_audio::uuid::kAudioStreamControlServiceUuid) {
        LOG(INFO) << "Found Audio Stream Endpoint service, handle: "
                  << loghex(tmp.handle);
        LOG_INFO(
            "Found Audio Stream Endpoint service, handle: 0x%04x, device: %s",
            tmp.handle, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
        ase_svc = &tmp;
      } else if (tmp.uuid == bluetooth::csis::kCsisServiceUuid) {
        LOG(INFO) << "Found CSIS service, handle: " << loghex(tmp.handle)
                  << " is primary? " << tmp.is_primary;
        LOG_INFO(
            "Found CSIS service, handle: 0x%04x, is primary: %d, device: %s",
            tmp.handle, tmp.is_primary,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
        if (tmp.is_primary) csis_primary_handles.push_back(tmp.handle);
      } else if (tmp.uuid == le_audio::uuid::kCapServiceUuid) {
        LOG(INFO) << "Found CAP Service, handle: " << loghex(tmp.handle);
        LOG_INFO("Found CAP service, handle: 0x%04x, device: %s", tmp.handle,
                 ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));

        /* Try to find context for CSIS instances */
        for (auto& included_srvc : tmp.included_services) {
@@ -2511,8 +2515,10 @@ class LeAudioClientImpl : public LeAudioClient {
          }
        }
      } else if (tmp.uuid == le_audio::uuid::kTelephonyMediaAudioServiceUuid) {
        LOG_INFO(", Found Telephony and Media Audio service, handle: %04x",
                 tmp.handle);
        LOG_INFO(
            "Found Telephony and Media Audio service, handle: 0x%04x, device: "
            "%s",
            tmp.handle, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
        tmas_svc = &tmp;
      }
    }
@@ -2563,9 +2569,11 @@ class LeAudioClientImpl : public LeAudioClient {
        leAudioDevice->snk_pacs_.push_back(std::make_tuple(
            hdl_pair, std::vector<struct le_audio::types::acs_ac_record>()));

        LOG(INFO) << "Found Sink PAC characteristic, handle: "
                  << loghex(charac.value_handle)
                  << ", ccc handle: " << loghex(hdl_pair.ccc_hdl);
        LOG_INFO(
            "Found Sink PAC characteristic, handle: 0x%04x, ccc handle: "
            "0x%04x, addr: %s",
            charac.value_handle, hdl_pair.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      } else if (charac.uuid ==
                 le_audio::uuid::
                     kSourcePublishedAudioCapabilityCharacteristicUuid) {
@@ -2593,9 +2601,11 @@ class LeAudioClientImpl : public LeAudioClient {
        leAudioDevice->src_pacs_.push_back(std::make_tuple(
            hdl_pair, std::vector<struct le_audio::types::acs_ac_record>()));

        LOG(INFO) << "Found Source PAC characteristic, handle: "
                  << loghex(charac.value_handle)
                  << ", ccc handle: " << loghex(hdl_pair.ccc_hdl);
        LOG_INFO(
            "Found Source PAC characteristic, handle: 0x%04x, ccc handle: "
            "0x%04x, addr: %s",
            charac.value_handle, hdl_pair.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      } else if (charac.uuid ==
                 le_audio::uuid::kSinkAudioLocationCharacteristicUuid) {
        leAudioDevice->snk_audio_locations_hdls_.val_hdl = charac.value_handle;
@@ -2621,9 +2631,12 @@ class LeAudioClientImpl : public LeAudioClient {
            conn_id, leAudioDevice->snk_audio_locations_hdls_.val_hdl,
            OnGattReadRspStatic, NULL);

        LOG(INFO) << "Found Sink audio locations characteristic, handle: "
                  << loghex(charac.value_handle) << ", ccc handle: "
                  << loghex(leAudioDevice->snk_audio_locations_hdls_.ccc_hdl);
        LOG_INFO(
            "Found Sink audio locations characteristic, handle: 0x%04x, ccc "
            "handle: 0x%04x, addr: %s",
            charac.value_handle,
            leAudioDevice->snk_audio_locations_hdls_.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      } else if (charac.uuid ==
                 le_audio::uuid::kSourceAudioLocationCharacteristicUuid) {
        leAudioDevice->src_audio_locations_hdls_.val_hdl = charac.value_handle;
@@ -2649,9 +2662,12 @@ class LeAudioClientImpl : public LeAudioClient {
            conn_id, leAudioDevice->src_audio_locations_hdls_.val_hdl,
            OnGattReadRspStatic, NULL);

        LOG(INFO) << "Found Source audio locations characteristic, handle: "
                  << loghex(charac.value_handle) << ", ccc handle: "
                  << loghex(leAudioDevice->src_audio_locations_hdls_.ccc_hdl);
        LOG_INFO(
            "Found Source audio locations characteristic, handle: 0x%04x, ccc "
            "handle: 0x%04x, addr: %s",
            charac.value_handle,
            leAudioDevice->src_audio_locations_hdls_.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      } else if (charac.uuid ==
                 le_audio::uuid::kAudioContextAvailabilityCharacteristicUuid) {
        leAudioDevice->audio_avail_hdls_.val_hdl = charac.value_handle;
@@ -2677,9 +2693,11 @@ class LeAudioClientImpl : public LeAudioClient {
            conn_id, leAudioDevice->audio_avail_hdls_.val_hdl,
            OnGattReadRspStatic, NULL);

        LOG(INFO) << "Found Audio Availability Context characteristic, handle: "
                  << loghex(charac.value_handle) << ", ccc handle: "
                  << loghex(leAudioDevice->audio_avail_hdls_.ccc_hdl);
        LOG_INFO(
            "Found Audio Availability Context characteristic, handle: 0x%04x, "
            "ccc handle: 0x%04x, addr: %s",
            charac.value_handle, leAudioDevice->audio_avail_hdls_.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      } else if (charac.uuid ==
                 le_audio::uuid::kAudioSupportedContextCharacteristicUuid) {
        leAudioDevice->audio_supp_cont_hdls_.val_hdl = charac.value_handle;
@@ -2704,9 +2722,11 @@ class LeAudioClientImpl : public LeAudioClient {
            conn_id, leAudioDevice->audio_supp_cont_hdls_.val_hdl,
            OnGattReadRspStatic, NULL);

        LOG(INFO) << "Found Audio Supported Context characteristic, handle: "
                  << loghex(charac.value_handle) << ", ccc handle: "
                  << loghex(leAudioDevice->audio_supp_cont_hdls_.ccc_hdl);
        LOG_INFO(
            "Found Audio Supported Context characteristic, handle: 0x%04x, ccc "
            "handle: 0x%04x, addr: %s",
            charac.value_handle, leAudioDevice->audio_supp_cont_hdls_.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      }
    }

@@ -2740,10 +2760,11 @@ class LeAudioClientImpl : public LeAudioClient {
        leAudioDevice->ases_.emplace_back(charac.value_handle, ccc_handle,
                                          direction);

        LOG(INFO) << "Found ASE characteristic, handle: "
                  << loghex(charac.value_handle)
                  << ", ccc handle: " << loghex(ccc_handle)
                  << ", direction: " << direction;
        LOG_INFO(
            "Found ASE characteristic, handle: 0x%04x, ccc handle: 0x%04x, "
            "direction: %d, addr: %s",
            charac.value_handle, ccc_handle, direction,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      } else if (charac.uuid ==
                 le_audio::uuid::
                     kAudioStreamEndpointControlPointCharacteristicUuid) {
@@ -2764,9 +2785,11 @@ class LeAudioClientImpl : public LeAudioClient {
          return;
        }

        LOG(INFO) << "Found ASE Control Point characteristic, handle: "
                  << loghex(charac.value_handle) << ", ccc handle: "
                  << loghex(leAudioDevice->ctp_hdls_.ccc_hdl);
        LOG_INFO(
            "Found ASE characteristic, handle: 0x%04x, ccc handle: 0x%04x, "
            "addr: %s",
            charac.value_handle, leAudioDevice->ctp_hdls_.ccc_hdl,
            ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      }
    }

@@ -2782,9 +2805,11 @@ class LeAudioClientImpl : public LeAudioClient {
                                           OnGattReadRspStatic, NULL);

          LOG_INFO(
              ", Found Telephony and Media Profile characteristic, "
              "handle: %04x",
              leAudioDevice->tmap_role_hdl_);
              "Found Telephony and Media Profile characteristic, handle: "
              "0x%04x, "
              "device: %s",
              leAudioDevice->tmap_role_hdl_,
              ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
        }
      }
    }
@@ -2849,8 +2874,8 @@ class LeAudioClientImpl : public LeAudioClient {
    }

    if (status == GATT_SUCCESS) {
      LOG(INFO) << __func__
                << ", successfully registered on ccc: " << loghex(hdl);
      LOG_INFO("Successfully registered on ccc: 0x%04x, device: %s", hdl,
               ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));

      if (leAudioDevice->ctp_hdls_.ccc_hdl == hdl &&
          leAudioDevice->known_service_handles_ &&
@@ -2863,9 +2888,10 @@ class LeAudioClientImpl : public LeAudioClient {
      return;
    }

    LOG(ERROR) << __func__
               << ", Failed to register for indications: " << loghex(hdl)
               << ", status: " << loghex((int)(status));
    LOG_ERROR(
        "Failed to register for indications: 0x%04x, device: %s, status: "
        "0x%02x",
        hdl, ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_), status);

    ase_it =
        std::find_if(leAudioDevice->ases_.begin(), leAudioDevice->ases_.end(),
@@ -2874,8 +2900,8 @@ class LeAudioClientImpl : public LeAudioClient {
                     });

    if (ase_it == leAudioDevice->ases_.end()) {
      LOG(ERROR) << __func__
                 << ", unknown ccc handle: " << static_cast<int>(hdl);
      LOG_ERROR("Unknown ccc handle: 0x%04x, device: %s", hdl,
                ADDRESS_TO_LOGGABLE_CSTR(leAudioDevice->address_));
      return;
    }