Loading system/bta/has/has_client.cc +25 −8 Original line number Diff line number Diff line Loading @@ -429,7 +429,7 @@ public: ClearDeviceInformationAndStartSearch(device); } else { log::error("Devices {}: Control point not usable. Disconnecting!", device->addr); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); } } Loading Loading @@ -475,7 +475,7 @@ public: ClearDeviceInformationAndStartSearch(device); } else { log::error("Devices {}: Control point not usable. Disconnecting!", device->addr); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); } } Loading Loading @@ -1137,7 +1137,7 @@ private: /* Both of these CCC are mandatory */ if (enabling_ntf && (status != GATT_SUCCESS)) { log::error("Failed to register for notifications on handle=0x{:x}", handle); BTA_GATTC_Close(conn_id); CleanAndDisconnectByConnId(conn_id); return; } } Loading Loading @@ -1189,20 +1189,22 @@ private: return; } tCONN_ID conn_id = device->conn_id; if (status != GATT_SUCCESS) { if (status == GATT_DATABASE_OUT_OF_SYNC) { log::info("Database out of sync for {}", device->addr); ClearDeviceInformationAndStartSearch(device); } else { log::error("Could not read characteristic at handle=0x{:04x}", handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); } return; } if (len != 1) { log::error("Invalid features value length={} at handle=0x{:x}", len, handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } Loading Loading @@ -1565,9 +1567,11 @@ private: void OnHasCtpValueNotification(HasDevice* device, uint16_t len, const uint8_t* value) { auto ntf_opt = HasCtpNtf::FromCharacteristicValue(len, value); tCONN_ID conn_id = device->conn_id; if (!ntf_opt.has_value()) { log::error("Unhandled notification for device: {}", *device); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } Loading @@ -1591,19 +1595,22 @@ private: return; } tCONN_ID conn_id = device->conn_id; if (status != GATT_SUCCESS) { if (status == GATT_DATABASE_OUT_OF_SYNC) { log::info("Database out of sync for {}", device->addr); ClearDeviceInformationAndStartSearch(device); } else { log::error("Could not read characteristic at handle=0x{:04x}", handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } } if (len != 1) { log::error("Invalid preset value length={} at handle=0x{:x}", len, handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } Loading Loading @@ -1717,6 +1724,16 @@ private: device.ConnectionCleanUp(); } void CleanAndDisconnectByConnId(tCONN_ID conn_id) { auto device_iter = std::find_if(devices_.begin(), devices_.end(), HasDevice::MatchConnId(conn_id)); if (device_iter != devices_.end()) { DoDisconnectCleanUp(*device_iter); devices_.erase(device_iter); } BTA_GATTC_Close(conn_id); } /* These below are all GATT service discovery, validation, cache & storage */ bool CacheAttributeHandles(const gatt::Service& service, HasDevice* device) { log::debug("device={}", device->addr); Loading system/bta/has/has_client_test.cc +35 −0 Original line number Diff line number Diff line Loading @@ -1602,6 +1602,41 @@ TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset_ntf) { TestConnect(test_address); } TEST_F(HasClientTest, test_cp_not_usable_read_all_presets) { 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); ON_CALL(gatt_queue, ReadCharacteristic(_, HasDbBuilder::kActivePresetIndexValHdl, _, _)) .WillByDefault(Invoke([&](uint16_t conn_id, uint16_t handle, GATT_READ_OP_CB cb, void* cb_data) -> void { std::vector<uint8_t> value; tGATT_STATUS status = GATT_ERROR; if (cb) { cb(conn_id, status, handle, value.size(), value.data(), cb_data); } })); EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded | bluetooth::has::kFeatureBitWritablePresets | bluetooth::has::kFeatureBitDynamicPresets)); EXPECT_CALL(gatt_queue, Clean(1)).Times(1); TestConnect(test_address); } TEST_F(HasClientTest, test_discovery_has_features_ntf) { const RawAddress test_address = GetTestAddress(1); auto test_conn_id = GetTestConnId(test_address); Loading Loading
system/bta/has/has_client.cc +25 −8 Original line number Diff line number Diff line Loading @@ -429,7 +429,7 @@ public: ClearDeviceInformationAndStartSearch(device); } else { log::error("Devices {}: Control point not usable. Disconnecting!", device->addr); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); } } Loading Loading @@ -475,7 +475,7 @@ public: ClearDeviceInformationAndStartSearch(device); } else { log::error("Devices {}: Control point not usable. Disconnecting!", device->addr); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); } } Loading Loading @@ -1137,7 +1137,7 @@ private: /* Both of these CCC are mandatory */ if (enabling_ntf && (status != GATT_SUCCESS)) { log::error("Failed to register for notifications on handle=0x{:x}", handle); BTA_GATTC_Close(conn_id); CleanAndDisconnectByConnId(conn_id); return; } } Loading Loading @@ -1189,20 +1189,22 @@ private: return; } tCONN_ID conn_id = device->conn_id; if (status != GATT_SUCCESS) { if (status == GATT_DATABASE_OUT_OF_SYNC) { log::info("Database out of sync for {}", device->addr); ClearDeviceInformationAndStartSearch(device); } else { log::error("Could not read characteristic at handle=0x{:04x}", handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); } return; } if (len != 1) { log::error("Invalid features value length={} at handle=0x{:x}", len, handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } Loading Loading @@ -1565,9 +1567,11 @@ private: void OnHasCtpValueNotification(HasDevice* device, uint16_t len, const uint8_t* value) { auto ntf_opt = HasCtpNtf::FromCharacteristicValue(len, value); tCONN_ID conn_id = device->conn_id; if (!ntf_opt.has_value()) { log::error("Unhandled notification for device: {}", *device); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } Loading @@ -1591,19 +1595,22 @@ private: return; } tCONN_ID conn_id = device->conn_id; if (status != GATT_SUCCESS) { if (status == GATT_DATABASE_OUT_OF_SYNC) { log::info("Database out of sync for {}", device->addr); ClearDeviceInformationAndStartSearch(device); } else { log::error("Could not read characteristic at handle=0x{:04x}", handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } } if (len != 1) { log::error("Invalid preset value length={} at handle=0x{:x}", len, handle); BTA_GATTC_Close(device->conn_id); CleanAndDisconnectByConnId(conn_id); return; } Loading Loading @@ -1717,6 +1724,16 @@ private: device.ConnectionCleanUp(); } void CleanAndDisconnectByConnId(tCONN_ID conn_id) { auto device_iter = std::find_if(devices_.begin(), devices_.end(), HasDevice::MatchConnId(conn_id)); if (device_iter != devices_.end()) { DoDisconnectCleanUp(*device_iter); devices_.erase(device_iter); } BTA_GATTC_Close(conn_id); } /* These below are all GATT service discovery, validation, cache & storage */ bool CacheAttributeHandles(const gatt::Service& service, HasDevice* device) { log::debug("device={}", device->addr); Loading
system/bta/has/has_client_test.cc +35 −0 Original line number Diff line number Diff line Loading @@ -1602,6 +1602,41 @@ TEST_F(HasClientTest, test_discovery_has_broken_no_active_preset_ntf) { TestConnect(test_address); } TEST_F(HasClientTest, test_cp_not_usable_read_all_presets) { 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); ON_CALL(gatt_queue, ReadCharacteristic(_, HasDbBuilder::kActivePresetIndexValHdl, _, _)) .WillByDefault(Invoke([&](uint16_t conn_id, uint16_t handle, GATT_READ_OP_CB cb, void* cb_data) -> void { std::vector<uint8_t> value; tGATT_STATUS status = GATT_ERROR; if (cb) { cb(conn_id, status, handle, value.size(), value.data(), cb_data); } })); EXPECT_CALL(*callbacks, OnDeviceAvailable(test_address, bluetooth::has::kFeatureBitHearingAidTypeBanded | bluetooth::has::kFeatureBitWritablePresets | bluetooth::has::kFeatureBitDynamicPresets)); EXPECT_CALL(gatt_queue, Clean(1)).Times(1); TestConnect(test_address); } TEST_F(HasClientTest, test_discovery_has_features_ntf) { const RawAddress test_address = GetTestAddress(1); auto test_conn_id = GetTestConnId(test_address); Loading