Loading system/bta/csis/csis_client.cc +52 −25 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); } } Loading Loading @@ -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); Loading @@ -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) { Loading @@ -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; Loading @@ -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 = Loading @@ -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 = Loading @@ -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)); } } Loading @@ -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; Loading Loading @@ -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); } Loading system/bta/csis/csis_client_test.cc +54 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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); Loading system/bta/csis/csis_types.h +17 −0 Original line number Diff line number Diff line Loading @@ -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_) { Loading system/bta/le_audio/client.cc +70 −44 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } } Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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_)); } } Loading Loading @@ -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) { Loading @@ -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_)); } } Loading @@ -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_)); } } } Loading Loading @@ -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_ && Loading @@ -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(), Loading @@ -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; } Loading Loading
system/bta/csis/csis_client.cc +52 −25 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); } } Loading Loading @@ -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); Loading @@ -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) { Loading @@ -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; Loading @@ -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 = Loading @@ -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 = Loading @@ -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)); } } Loading @@ -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; Loading Loading @@ -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); } Loading
system/bta/csis/csis_client_test.cc +54 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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); Loading
system/bta/csis/csis_types.h +17 −0 Original line number Diff line number Diff line Loading @@ -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_) { Loading
system/bta/le_audio/client.cc +70 −44 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } } Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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_)); } } Loading Loading @@ -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) { Loading @@ -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_)); } } Loading @@ -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_)); } } } Loading Loading @@ -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_ && Loading @@ -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(), Loading @@ -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; } Loading