diff options
32 files changed, 1016 insertions, 273 deletions
diff --git a/flags/Android.bp b/flags/Android.bp index f2e05999cf..02c5381966 100644 --- a/flags/Android.bp +++ b/flags/Android.bp @@ -10,6 +10,7 @@ aconfig_declarations { // LINT.IfChange srcs: [ "a2dp.aconfig", + "active_device_manager.aconfig", "asha.aconfig", "audio_routing.aconfig", "avrcp.aconfig", diff --git a/flags/BUILD.gn b/flags/BUILD.gn index 319b1b8d14..6e42632f8a 100644 --- a/flags/BUILD.gn +++ b/flags/BUILD.gn @@ -4,6 +4,7 @@ aconfig("bluetooth_flags_c_lib") { # LINT.IfChange sources = [ "a2dp.aconfig", + "active_device_manager.aconfig", "asha.aconfig", "audio_routing.aconfig", "avrcp.aconfig", diff --git a/flags/active_device_manager.aconfig b/flags/active_device_manager.aconfig new file mode 100644 index 0000000000..4995951d37 --- /dev/null +++ b/flags/active_device_manager.aconfig @@ -0,0 +1,9 @@ +package: "com.android.bluetooth.flags" +container: "com.android.btservices" + +flag { + name: "fallback_when_wired_audio_disconnected" + namespace: "bluetooth" + description: "Fallback to other connected device when wired audio device disconnects" + bug: "348124361" +} diff --git a/flags/bta_dm.aconfig b/flags/bta_dm.aconfig index 30264909db..8868063d53 100644 --- a/flags/bta_dm.aconfig +++ b/flags/bta_dm.aconfig @@ -9,20 +9,6 @@ flag { } flag { - name: "connect_hid_after_service_discovery" - namespace: "bluetooth" - description: "Don't initiate HID connection before pairing and service discovery" - bug: "314707251" -} - -flag { - name: "bta_dm_disc_stuck_in_cancelling_fix" - namespace: "bluetooth" - description: "Fix being stuck in BTA_DM_SEARCH_CANCELLING" - bug: "319890673" -} - -flag { name: "bta_dm_defer_device_discovery_state_change_until_rnr_complete" namespace: "bluetooth" description: "Fix double-sending device discovery state change when canceling RNR" diff --git a/flags/btif_dm.aconfig b/flags/btif_dm.aconfig index 670036a9b4..9000dfe30b 100644 --- a/flags/btif_dm.aconfig +++ b/flags/btif_dm.aconfig @@ -2,27 +2,6 @@ package: "com.android.bluetooth.flags" container: "com.android.btservices" flag { - name: "ignore_bond_type_for_le" - namespace: "bluetooth" - description: "Bond type is not applicable for LE SMP pairing" - bug: "319695663" -} - -flag { - name: "reset_pairing_only_for_related_service_discovery" - namespace: "bluetooth" - description: "Don't reset the pairing state if service discovery concludes for a different device" - bug: "321996502" -} - -flag { - name: "force_bredr_for_sdp_retry" - namespace: "bluetooth" - description: "Force BR/EDR transport for retrying SDP service discovery" - bug: "326656580" -} - -flag { name: "do_not_replace_existing_cod_with_uncategorized_cod" namespace: "bluetooth" description: "Don't replace an existing stored class of device with one determined to be uncategorized" diff --git a/flags/hfp.aconfig b/flags/hfp.aconfig index 9c853c6f67..dabe666bfa 100644 --- a/flags/hfp.aconfig +++ b/flags/hfp.aconfig @@ -115,3 +115,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "ignore_notify_when_already_connected" + namespace: "bluetooth" + description: "Flag to ignore connect state notification from Native to Java layer when already connected" + bug: "346679106" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig index da3ab5b77d..6cbf08fd5a 100644 --- a/flags/pairing.aconfig +++ b/flags/pairing.aconfig @@ -54,3 +54,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "pairing_name_discovery_addresss_mismatch" + namespace: "bluetooth" + description: "Do not abort pairing if name discovery for a another device fails" + bug: "349144497" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/flags/security.aconfig b/flags/security.aconfig index f6ff588ae6..0f1261df2c 100644 --- a/flags/security.aconfig +++ b/flags/security.aconfig @@ -30,13 +30,6 @@ flag { } flag { - name: "fix_pairing_failure_reason_from_remote" - namespace: "bluetooth" - description: "Correct the pairing failure reason reported from remote" - bug: "320745565" -} - -flag { name: "fix_le_oob_pairing_bypass" namespace: "bluetooth" description: "Fix oob bypassing bug in SMP" diff --git a/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt b/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt index ab3e13ffee..d8864b161c 100644 --- a/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt +++ b/framework/tests/bumble/src/android/bluetooth/DckGattTest.kt @@ -250,7 +250,7 @@ public class DckGattTest() { // Verify correct scan result as prerequisite val scanResult = scanResultCaptor.firstValue assertThat(scanResult).isNotNull() - assertThat(scanResult.device.identityAddress).isEqualTo(TEST_ADDRESS_RANDOM_STATIC) + assertThat(scanResult.device.address).isEqualTo(TEST_ADDRESS_RANDOM_STATIC) // Verify successful GATT connection val device = scanResult.device diff --git a/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java b/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java index d5002b63c5..aad18d7c51 100644 --- a/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java +++ b/framework/tests/bumble/src/android/bluetooth/pairing/PairingTest.java @@ -39,7 +39,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.ParcelUuid; -import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Log; @@ -47,7 +46,6 @@ import android.util.Log; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import io.grpc.stub.StreamObserver; @@ -306,7 +304,6 @@ public class PairingTest { * Expectation: Pairing gets cancelled instead of getting timed out */ @Test - @RequiresFlagsEnabled(Flags.FLAG_RESET_PAIRING_ONLY_FOR_RELATED_SERVICE_DISCOVERY) public void testCancelBondLe_WithGattServiceDiscovery() { registerIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED); @@ -357,7 +354,6 @@ public class PairingTest { * Expectation: Pairing succeeds */ @Test - @RequiresFlagsEnabled(Flags.FLAG_RESET_PAIRING_ONLY_FOR_RELATED_SERVICE_DISCOVERY) public void testBondLe_WithGattServiceDiscovery() { registerIntentActions(BluetoothDevice.ACTION_BOND_STATE_CHANGED); diff --git a/framework/tests/util/src/Permissions.kt b/framework/tests/util/src/Permissions.kt index ee8b60f224..9e25d30e8b 100644 --- a/framework/tests/util/src/Permissions.kt +++ b/framework/tests/util/src/Permissions.kt @@ -64,6 +64,8 @@ object Permissions { private fun restorePermissions(permissions: Set<String>) { if (UiAutomation.ALL_PERMISSIONS.equals(permissions)) { uiAutomation.adoptShellPermissionIdentity() + } else if (permissions.size == 0) { + uiAutomation.dropShellPermissionIdentity() } else { uiAutomation.adoptShellPermissionIdentity(*permissions.map { it }.toTypedArray()) } diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc index b8e24551db..37840398b9 100644 --- a/system/bta/dm/bta_dm_disc.cc +++ b/system/bta/dm/bta_dm_disc.cc @@ -617,12 +617,9 @@ static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) { } else { bta_dm_discovery_cb.conn_id = GATT_INVALID_CONN_ID; - if (com::android::bluetooth::flags::bta_dm_disc_stuck_in_cancelling_fix()) { - log::info( - "Discovery complete for invalid conn ID. Will pick up next job"); - bta_dm_discovery_set_state(BTA_DM_DISCOVER_IDLE); - bta_dm_execute_queued_discovery_request(); - } + log::info("Discovery complete for invalid conn ID. Will pick up next job"); + bta_dm_discovery_set_state(BTA_DM_DISCOVER_IDLE); + bta_dm_execute_queued_discovery_request(); } } diff --git a/system/bta/dm/bta_dm_disc_legacy.cc b/system/bta/dm/bta_dm_disc_legacy.cc index 853fbc3224..6713ade8c6 100644 --- a/system/bta/dm/bta_dm_disc_legacy.cc +++ b/system/bta/dm/bta_dm_disc_legacy.cc @@ -1836,13 +1836,10 @@ static void bta_dm_gatt_disc_complete(uint16_t conn_id, tGATT_STATUS status) { } else { bta_dm_search_cb.conn_id = GATT_INVALID_CONN_ID; - if (com::android::bluetooth::flags::bta_dm_disc_stuck_in_cancelling_fix()) { - log::info( - "Discovery complete for invalid conn ID. Will pick up next job"); - bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); - bta_dm_free_sdp_db(); - bta_dm_execute_queued_request(); - } + log::info("Discovery complete for invalid conn ID. Will pick up next job"); + bta_dm_search_set_state(BTA_DM_SEARCH_IDLE); + bta_dm_free_sdp_db(); + bta_dm_execute_queued_request(); } } diff --git a/system/bta/hearing_aid/hearing_aid.cc b/system/bta/hearing_aid/hearing_aid.cc index 223af0966f..2f98063198 100644 --- a/system/bta/hearing_aid/hearing_aid.cc +++ b/system/bta/hearing_aid/hearing_aid.cc @@ -1100,7 +1100,17 @@ class HearingAidImpl : public HearingAid { : BTM_SEC_SERVICE_HEARING_AID_RIGHT; uint16_t gap_handle = GAP_ConnOpen( "", service_id, false, &hearingDevice->address, psm, 514 /* MPS */, - &cfg_info, nullptr, BTM_SEC_NONE /* TODO: request security ? */, + &cfg_info, nullptr, + /// b/309483354: + /// Encryption needs to be explicitly requested at channel + /// establishment even though validation is performed in this module + /// because of re-connection logic present in the L2CAP module. + /// The L2CAP will automatically reconnect the LE-ACL link on + /// disconnection when there is a pending channel request, + /// which invalidates all encryption checks performed here. + com::android::bluetooth::flags::asha_asrc() + ? BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_ENCRYPT + : BTM_SEC_NONE, HearingAidImpl::GapCallbackStatic, BT_TRANSPORT_LE); if (gap_handle == GAP_INVALID_HANDLE) { diff --git a/system/bta/hf_client/bta_hf_client_at.cc b/system/bta/hf_client/bta_hf_client_at.cc index 2d44cb45fd..58daf4a605 100644 --- a/system/bta/hf_client/bta_hf_client_at.cc +++ b/system/bta/hf_client/bta_hf_client_at.cc @@ -1920,7 +1920,7 @@ void bta_hf_client_send_at_biev(tBTA_HF_CLIENT_CB* client_cb, int indicator_id, char buf[32]; tBTA_HF_CLIENT_AT_CMD cmd = BTA_HF_CLIENT_AT_BIEV; - if ((client_cb->peer_features & BTA_HF_CLIENT_FEAT_HF_IND) == 0) { + if ((client_cb->peer_features & BTA_HF_CLIENT_PEER_HF_IND) == 0) { log::error("peer does not support HF Indicators"); return; } diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc index b865865544..5aa081e8a3 100644 --- a/system/bta/le_audio/client.cc +++ b/system/bta/le_audio/client.cc @@ -1160,12 +1160,19 @@ class LeAudioClientImpl : public LeAudioClient { L2CA_SetEcosystemBaseInterval(frame_duration_us / 1250); - audio_framework_source_config.data_interval_us = frame_duration_us; + // Scale by the codec frame blocks per SDU if set + uint8_t codec_frame_blocks_per_sdu = + group->stream_conf.stream_params.source.codec_frames_blocks_per_sdu + ?: 1; + audio_framework_source_config.data_interval_us = + frame_duration_us * codec_frame_blocks_per_sdu; + le_audio_source_hal_client_->Start(audio_framework_source_config, audioSinkReceiver, dsa_modes); /* We use same frame duration for sink/source */ - audio_framework_sink_config.data_interval_us = frame_duration_us; + audio_framework_sink_config.data_interval_us = + frame_duration_us * codec_frame_blocks_per_sdu; /* If group supports more than 16kHz for the microphone in converstional * case let's use that also for Audio Framework. @@ -3393,6 +3400,12 @@ class LeAudioClientImpl : public LeAudioClient { right_cis_handle = cis_handle; } + if (stream_params.codec_frames_blocks_per_sdu != 1) { + log::error( + "Codec Frame Blocks of {} is not supported by the software encoding", + +stream_params.codec_frames_blocks_per_sdu); + } + uint16_t byte_count = stream_params.octets_per_codec_frame; bool mix_to_mono = (left_cis_handle == 0) || (right_cis_handle == 0); if (mix_to_mono) { @@ -3441,6 +3454,12 @@ class LeAudioClientImpl : public LeAudioClient { return; } + if (stream_params.codec_frames_blocks_per_sdu != 1) { + log::error( + "Codec Frame Blocks of {} is not supported by the software encoding", + +stream_params.codec_frames_blocks_per_sdu); + } + uint16_t byte_count = stream_params.octets_per_codec_frame; bool mix_to_mono = (num_channels == 1); if (mix_to_mono) { diff --git a/system/bta/le_audio/devices_test.cc b/system/bta/le_audio/devices_test.cc index 79290fc1cd..ea6f4421a1 100644 --- a/system/bta/le_audio/devices_test.cc +++ b/system/bta/le_audio/devices_test.cc @@ -718,12 +718,15 @@ class LeAudioAseConfigurationTest // configurations ON_CALL(*mock_codec_manager_, IsDualBiDirSwbSupported) .WillByDefault(Return(true)); - ON_CALL(*mock_codec_manager_, GetCodecConfig) - .WillByDefault(Invoke( - [](const bluetooth::le_audio::CodecManager:: - UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier - verifier) { + } + + ON_CALL(*mock_codec_manager_, GetCodecConfig) + .WillByDefault(Invoke( + [&](const bluetooth::le_audio::CodecManager:: + UnicastConfigurationRequirements& requirements, + bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier + verifier) { + if (codec_coding_format_ == kLeAudioCodingFormatLC3) { auto filtered = *bluetooth::le_audio::AudioSetConfigurationProvider::Get() ->GetConfigurations(requirements.audio_context_type); @@ -745,18 +748,10 @@ class LeAudioAseConfigurationTest return std::unique_ptr<AudioSetConfiguration>(nullptr); } return std::make_unique<AudioSetConfiguration>(*cfg); - })); - } else { - // Provide a configuration for the vendor codec - ON_CALL(*mock_codec_manager_, GetCodecConfig) - .WillByDefault(Invoke( - [](const bluetooth::le_audio::CodecManager:: - UnicastConfigurationRequirements& requirements, - bluetooth::le_audio::CodecManager::UnicastConfigurationVerifier - verifier) { + } else { return MockVendorCodecProvider(requirements); - })); - } + } + })); ON_CALL(*mock_codec_manager_, CheckCodecConfigIsBiDirSwb) .WillByDefault(Invoke([](const bluetooth::le_audio::set_configurations:: @@ -1125,7 +1120,8 @@ class LeAudioAseConfigurationTest } void TestAsesActive(LeAudioCodecId codec_id, uint8_t sampling_frequency, - uint8_t frame_duration, uint16_t octets_per_frame) { + uint8_t frame_duration, uint16_t octets_per_frame, + uint8_t codec_frame_blocks_per_sdu = 1) { bool active_ase = false; for (const auto& device : devices_) { @@ -1144,6 +1140,8 @@ class LeAudioAseConfigurationTest ASSERT_EQ(core_config.sampling_frequency, sampling_frequency); ASSERT_EQ(core_config.frame_duration, frame_duration); ASSERT_EQ(core_config.octets_per_codec_frame, octets_per_frame); + ASSERT_EQ(core_config.codec_frames_blocks_per_sdu.value_or(0), + codec_frame_blocks_per_sdu); } } } @@ -1177,7 +1175,8 @@ class LeAudioAseConfigurationTest } } - void TestLc3CodecConfig(LeAudioContextType context_type) { + void TestLc3CodecConfig(LeAudioContextType context_type, + uint8_t max_codec_frames_per_sdu = 1) { for (int i = Lc3SettingIdBegin; i < Lc3SettingIdEnd; i++) { // test each configuration parameter against valid and invalid value std::array<Lc3SettingId, 2> test_variants = {static_cast<Lc3SettingId>(i), @@ -1198,7 +1197,7 @@ class LeAudioAseConfigurationTest frame_duration, kLeAudioCodecChannelCountSingleChannel | kLeAudioCodecChannelCountTwoChannel, - octets_per_frame); + octets_per_frame, max_codec_frames_per_sdu); for (auto& device : devices_) { /* For simplicity configure both PACs with the same parameters*/ @@ -1224,7 +1223,8 @@ class LeAudioAseConfigurationTest group_->Configure(context_type, group_audio_locations)); if (success_expected) { TestAsesActive(LeAudioCodecIdLc3, sampling_frequency, - frame_duration, octets_per_frame); + frame_duration, octets_per_frame, + max_codec_frames_per_sdu); group_->Deactivate(); } @@ -2072,6 +2072,74 @@ TEST_P(LeAudioAseConfigurationTest, test_lc3_config_media) { TestLc3CodecConfig(LeAudioContextType::MEDIA); } +TEST_P(LeAudioAseConfigurationTest, + test_lc3_config_media_codec_extensibility_fb2) { + if (codec_coding_format_ != kLeAudioCodingFormatLC3) GTEST_SKIP(); + + bool is_fb2_passed_as_requirement = false; + auto max_codec_frames_per_sdu = 2; + + // Mock the configuration provider to give us config with 2 frame blocks per + // SDU if it receives the proper PAC entry in the requirements + // ON_CALL(*mock_codec_manager_, IsUsingCodecExtensibility) + // .WillByDefault(Return(true)); + ON_CALL(*mock_codec_manager_, GetCodecConfig) + .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager:: + UnicastConfigurationRequirements& + requirements, + bluetooth::le_audio::CodecManager:: + UnicastConfigurationVerifier verifier) { + auto filtered = + *bluetooth::le_audio::AudioSetConfigurationProvider::Get() + ->GetConfigurations(requirements.audio_context_type); + // Filter out the dual bidir SWB configurations + if (!bluetooth::le_audio::CodecManager::GetInstance() + ->IsDualBiDirSwbSupported()) { + filtered.erase( + std::remove_if(filtered.begin(), filtered.end(), + [](auto const& el) { + if (el->confs.source.empty()) return false; + return AudioSetConfigurationProvider::Get() + ->CheckConfigurationIsDualBiDirSwb(*el); + }), + filtered.end()); + } + auto cfg = verifier(requirements, &filtered); + if (cfg == nullptr) { + return std::unique_ptr<AudioSetConfiguration>(nullptr); + } + + auto config = *cfg; + + if (requirements.sink_pacs.has_value()) { + for (auto const& rec : requirements.sink_pacs.value()) { + auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities(); + if (caps.HasSupportedMaxCodecFramesPerSdu()) { + if (caps.supported_max_codec_frames_per_sdu.value() == + max_codec_frames_per_sdu) { + // Inject the proper Codec Frames Per SDU as the json + // configs are conservative and will always give us 1 + for (auto& entry : config.confs.sink) { + entry.codec.params.Add( + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, + (uint8_t)max_codec_frames_per_sdu); + } + is_fb2_passed_as_requirement = true; + } + } + } + } + return std::make_unique<AudioSetConfiguration>(config); + })); + + AddTestDevice(1, 1); + + TestLc3CodecConfig(LeAudioContextType::MEDIA, max_codec_frames_per_sdu); + + // Make sure the CodecManager mock gets the proper PAC record + ASSERT_TRUE(is_fb2_passed_as_requirement); +} + TEST_P(LeAudioAseConfigurationTest, test_unsupported_codec) { if (codec_coding_format_ == kLeAudioCodingFormatVendorSpecific) GTEST_SKIP(); diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc index 8cd07f856d..a216a4acc4 100644 --- a/system/bta/le_audio/le_audio_client_test.cc +++ b/system/bta/le_audio/le_audio_client_test.cc @@ -30,6 +30,7 @@ #include "bta_groups.h" #include "bta_le_audio_api.h" #include "bta_le_audio_broadcaster_api.h" +#include "btif/include/mock_core_callbacks.h" #include "btif_storage_mock.h" #include "btm_api_mock.h" #include "btm_iso_api.h" @@ -41,6 +42,7 @@ #include "hci/controller_interface_mock.h" #include "internal_include/stack_config.h" #include "le_audio/codec_manager.h" +#include "le_audio/mock_codec_interface.h" #include "le_audio_health_status.h" #include "le_audio_set_configuration_provider.h" #include "le_audio_types.h" @@ -1156,6 +1158,8 @@ class UnicastTestNoInit : public Test { stream_conf->stream_params.source .codec_frames_blocks_per_sdu = *core_config.codec_frames_blocks_per_sdu; + stream_conf->stream_params.source.frame_duration_us = + core_config.GetFrameDurationUs(); } else { log::assert_that( stream_conf->stream_params.source @@ -1228,6 +1232,8 @@ class UnicastTestNoInit : public Test { stream_conf->stream_params.sink .codec_frames_blocks_per_sdu = *core_config.codec_frames_blocks_per_sdu; + stream_conf->stream_params.sink.frame_duration_us = + core_config.GetFrameDurationUs(); } else { log::assert_that( stream_conf->stream_params.sink @@ -2347,6 +2353,25 @@ class UnicastTestNoInit : public Test { std::move(ascs), std::move(pacs)); } + struct SampleDatabaseParameters { + uint16_t conn_id; + RawAddress addr; + + uint32_t sink_audio_allocation = codec_spec_conf::kLeAudioLocationStereo; + uint32_t source_audio_allocation = codec_spec_conf::kLeAudioLocationStereo; + uint8_t sink_channel_cnt = 0x03; + uint8_t source_channel_cnt = 0x03; + uint16_t sample_freq_mask = 0x0004; + bool add_csis = true; + bool add_cas = true; + bool add_pacs = true; + int add_ascs_cnt = 1; + uint8_t set_size = 2; + uint8_t rank = 1; + GattStatus gatt_status = GATT_SUCCESS; + uint8_t max_supported_codec_frames_per_sdu = 1; + }; + void SetSampleDatabaseEarbudsValid( uint16_t conn_id, RawAddress addr, uint32_t sink_audio_allocation, uint32_t source_audio_allocation, uint8_t sink_channel_cnt = 0x03, @@ -2354,6 +2379,43 @@ class UnicastTestNoInit : public Test { bool add_csis = true, bool add_cas = true, bool add_pacs = true, int add_ascs_cnt = 1, uint8_t set_size = 2, uint8_t rank = 1, GattStatus gatt_status = GATT_SUCCESS) { + SetSampleDatabaseEarbudsValid(SampleDatabaseParameters{ + .conn_id = conn_id, + .addr = addr, + .sink_audio_allocation = sink_audio_allocation, + .source_audio_allocation = source_audio_allocation, + .sink_channel_cnt = sink_channel_cnt, + .source_channel_cnt = source_channel_cnt, + .sample_freq_mask = sample_freq_mask, + .add_csis = add_csis, + .add_cas = add_cas, + .add_pacs = add_pacs, + .add_ascs_cnt = add_ascs_cnt, + .set_size = set_size, + .rank = rank, + .gatt_status = gatt_status, + .max_supported_codec_frames_per_sdu = 1, + }); + } + + void SetSampleDatabaseEarbudsValid(const SampleDatabaseParameters& params) { + auto conn_id = params.conn_id; + auto addr = params.addr; + auto sink_audio_allocation = params.sink_audio_allocation; + auto source_audio_allocation = params.source_audio_allocation; + auto sink_channel_cnt = params.sink_channel_cnt; + auto source_channel_cnt = params.source_channel_cnt; + auto sample_freq_mask = params.sample_freq_mask; + auto add_csis = params.add_csis; + auto add_cas = params.add_cas; + auto add_pacs = params.add_pacs; + auto add_ascs_cnt = params.add_ascs_cnt; + auto set_size = params.set_size; + auto rank = params.rank; + auto gatt_status = params.gatt_status; + auto max_supported_codec_frames_per_sdu = + params.max_supported_codec_frames_per_sdu; + auto csis = std::make_unique<NiceMock<MockDeviceWrapper::csis_mock>>(); if (add_csis) { // attribute handles @@ -2451,10 +2513,8 @@ class UnicastTestNoInit : public Test { // Set pacs default read values ON_CALL(*peer_devices.at(conn_id)->pacs, OnReadCharacteristic(_, _, _)) - .WillByDefault([this, conn_id, snk_allocation, src_allocation, - sample_freq, sink_channel_cnt, source_channel_cnt, - gatt_status](uint16_t handle, GATT_READ_OP_CB cb, - void* cb_data) { + .WillByDefault([=, this](uint16_t handle, GATT_READ_OP_CB cb, + void* cb_data) { auto& pacs = peer_devices.at(conn_id)->pacs; std::vector<uint8_t> value; if (gatt_status == GATT_SUCCESS) { @@ -2498,7 +2558,7 @@ class UnicastTestNoInit : public Test { 0x00, 0x00, // Codec Spec. Caps. Len - 0x10, + 0x13, 0x03, /* sample freq */ 0x01, 0x80, /* 48kHz */ @@ -2515,6 +2575,9 @@ class UnicastTestNoInit : public Test { 0x00, 0x78, 0x00, + 0x02, /* Max supported codec frames per SDU */ + 0x05, + max_supported_codec_frames_per_sdu, // Metadata Length 0x00, }; @@ -2900,6 +2963,8 @@ class UnicastTest : public UnicastTestNoInit { } void TearDown() override { + MockCodecInterface::ClearMockInstanceHookList(); + // Clear the default actions before the parent class teardown is called Mock::VerifyAndClear(&mock_btm_interface_); Mock::VerifyAndClear(&mock_gatt_interface_); @@ -10882,4 +10947,186 @@ TEST_F_WITH_FLAGS(UnicastTest, NoContextvalidateStreamingRequest, Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_); } + +TEST_F(UnicastTest, CodecFrameBlocks2) { + auto const max_codec_frames_per_sdu = 2; + uint32_t data_len = 1920; + + // Register a on-the-fly hook for codec interface mock mutation to prepare the + // codec mock for encoding + std::list<MockCodecInterface*> codec_mocks; + MockCodecInterface::RegisterMockInstanceHook([&](MockCodecInterface* mock, + bool is_destroyed) { + if (is_destroyed) { + log::debug("Codec Interface Destroyed: {}", (long)mock); + codec_mocks.remove(mock); + } else { + log::debug("Codec Interface Created: {}", (long)mock); + ON_CALL(*mock, GetNumOfSamplesPerChannel()).WillByDefault(Return(960)); + ON_CALL(*mock, GetNumOfBytesPerSample()) + .WillByDefault(Return(2)); // 16bits samples + ON_CALL(*mock, Encode(_, _, _, _, _)) + .WillByDefault(Return(CodecInterface::Status::STATUS_OK)); + codec_mocks.push_back(mock); + } + }); + + // Add a frame block PAC passing verifier + bool is_fb2_passed_as_requirement = false; + ON_CALL(*mock_codec_manager_, GetCodecConfig) + .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager:: + UnicastConfigurationRequirements& + requirements, + bluetooth::le_audio::CodecManager:: + UnicastConfigurationVerifier verifier) { + auto filtered = + *bluetooth::le_audio::AudioSetConfigurationProvider::Get() + ->GetConfigurations(requirements.audio_context_type); + // Filter out the dual bidir SWB configurations + if (!bluetooth::le_audio::CodecManager::GetInstance() + ->IsDualBiDirSwbSupported()) { + filtered.erase( + std::remove_if(filtered.begin(), filtered.end(), + [](auto const& el) { + if (el->confs.source.empty()) return false; + return AudioSetConfigurationProvider::Get() + ->CheckConfigurationIsDualBiDirSwb(*el); + }), + filtered.end()); + } + auto cfg = verifier(requirements, &filtered); + if (cfg == nullptr) { + return std::unique_ptr<set_configurations::AudioSetConfiguration>( + nullptr); + } + + auto config = *cfg; + + if (requirements.sink_pacs.has_value()) { + for (auto const& rec : requirements.sink_pacs.value()) { + auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities(); + if (caps.HasSupportedMaxCodecFramesPerSdu()) { + if (caps.supported_max_codec_frames_per_sdu.value() == + max_codec_frames_per_sdu) { + // Inject the proper Codec Frames Per SDU as the json + // configs are conservative and will always give us 1 + for (auto& entry : config.confs.sink) { + entry.codec.params.Add( + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, + (uint8_t)max_codec_frames_per_sdu); + } + is_fb2_passed_as_requirement = true; + } + } + } + } + return std::make_unique<set_configurations::AudioSetConfiguration>( + config); + })); + + types::BidirectionalPair<stream_parameters> codec_manager_stream_params; + ON_CALL(*mock_codec_manager_, UpdateActiveAudioConfig) + .WillByDefault(Invoke( + [&](const types::BidirectionalPair<stream_parameters>& stream_params, + types::BidirectionalPair<uint16_t> delays_ms, + std::function<void(const offload_config& config, + uint8_t direction)> + updater) { codec_manager_stream_params = stream_params; })); + + const RawAddress test_address0 = GetTestAddress(0); + int group_id = bluetooth::groups::kGroupUnknown; + + SampleDatabaseParameters remote_params{ + .conn_id = 1, + .addr = test_address0, + .add_csis = false, + .set_size = 0, + .rank = 0, + .max_supported_codec_frames_per_sdu = 2, + }; + SetSampleDatabaseEarbudsValid(remote_params); + + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnConnectionState(ConnectionState::CONNECTED, test_address0)) + .Times(1); + EXPECT_CALL(mock_audio_hal_client_callbacks_, + OnGroupNodeStatus(test_address0, _, GroupNodeStatus::ADDED)) + .WillOnce(DoAll(SaveArg<1>(&group_id))); + + ConnectLeAudio(test_address0); + ASSERT_NE(group_id, bluetooth::groups::kGroupUnknown); + + constexpr int gmcs_ccid = 1; + constexpr int gtbs_ccid = 2; + + // Audio sessions are started only when device gets active + EXPECT_CALL(*mock_le_audio_source_hal_client_, Start(_, _, _)).Times(1); + EXPECT_CALL(*mock_le_audio_sink_hal_client_, Start(_, _, _)).Times(1); + LeAudioClient::Get()->SetCcidInformation(gmcs_ccid, 4 /* Media */); + LeAudioClient::Get()->SetCcidInformation(gtbs_ccid, 2 /* Phone */); + LeAudioClient::Get()->GroupSetActive(group_id); + SyncOnMainLoop(); + + types::BidirectionalPair<std::vector<uint8_t>> ccids = {.sink = {gmcs_ccid}, + .source = {}}; + EXPECT_CALL(mock_state_machine_, StartStream(_, _, _, ccids)).Times(1); + + block_streaming_state_callback = true; + + UpdateLocalSourceMetadata(AUDIO_USAGE_MEDIA, AUDIO_CONTENT_TYPE_MUSIC); + LocalAudioSourceResume(false); + + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_audio_hal_client_callbacks_); + Mock::VerifyAndClearExpectations(mock_le_audio_source_hal_client_); + ASSERT_TRUE(is_fb2_passed_as_requirement); + + // Verify codec fram blocks per SDU has been applied to the device + ASSERT_NE(0lu, streaming_groups.count(group_id)); + uint8_t device_configured_codec_frame_blocks_per_sdu = 0; + auto group = streaming_groups.at(group_id); + for (LeAudioDevice* device = group->GetFirstDevice(); device != nullptr; + device = group->GetNextDevice(device)) { + for (auto& ase : device->ases_) { + if (ase.active) { + auto cfg = ase.codec_config.GetAsCoreCodecConfig(); + ASSERT_TRUE(cfg.codec_frames_blocks_per_sdu.has_value()); + device_configured_codec_frame_blocks_per_sdu = + cfg.codec_frames_blocks_per_sdu.value(); + } + } + } + + // Verify the configured codec frame blocks per SDU + ASSERT_EQ(device_configured_codec_frame_blocks_per_sdu, + remote_params.max_supported_codec_frames_per_sdu); + + EXPECT_CALL(mock_state_machine_, StopStream(_)).Times(0); + do_in_main_thread( + FROM_HERE, + base::BindOnce( + [](int group_id, + bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks* + state_machine_callbacks) { + state_machine_callbacks->StatusReportCb( + group_id, GroupStreamStatus::STREAMING); + }, + group_id, base::Unretained(state_machine_callbacks_))); + SyncOnMainLoop(); + Mock::VerifyAndClearExpectations(&mock_state_machine_); + + // Verify Data transfer on one audio source cis + constexpr uint8_t cis_count_out = 1; + constexpr uint8_t cis_count_in = 0; + TestAudioDataTransfer( + group_id, cis_count_out, cis_count_in, + data_len * device_configured_codec_frame_blocks_per_sdu); + + ASSERT_NE(codec_mocks.size(), 0ul); + + // Verify that the initially started session was updated with the new params + ASSERT_EQ(codec_manager_stream_params.sink.codec_frames_blocks_per_sdu, + max_codec_frames_per_sdu); +} + } // namespace bluetooth::le_audio diff --git a/system/bta/le_audio/le_audio_types.cc b/system/bta/le_audio/le_audio_types.cc index 67a8a58276..21337cba12 100644 --- a/system/bta/le_audio/le_audio_types.cc +++ b/system/bta/le_audio/le_audio_types.cc @@ -133,7 +133,9 @@ uint32_t CodecConfigSetting::GetSamplingFrequencyHz() const { uint32_t CodecConfigSetting::GetDataIntervalUs() const { switch (id.coding_format) { case kLeAudioCodingFormatLC3: - return params.GetAsCoreCodecConfig().GetFrameDurationUs(); + return params.GetAsCoreCodecConfig().GetFrameDurationUs() * + params.GetAsCoreCodecConfig().codec_frames_blocks_per_sdu.value_or( + 1); default: log::warn(", invalid codec id: 0x{:02x}", id.coding_format); return 0; diff --git a/system/bta/le_audio/mock_codec_interface.cc b/system/bta/le_audio/mock_codec_interface.cc index 71b26e2bfa..0c8af03767 100644 --- a/system/bta/le_audio/mock_codec_interface.cc +++ b/system/bta/le_audio/mock_codec_interface.cc @@ -16,6 +16,11 @@ #include "mock_codec_interface.h" +#include "le_audio/codec_interface.h" + +static std::list<std::function<void(MockCodecInterface*, bool)>> + mock_life_listener_list; + namespace bluetooth::le_audio { struct CodecInterface::Impl : public MockCodecInterface { @@ -31,8 +36,16 @@ struct CodecInterface::Impl : public MockCodecInterface { CodecInterface::CodecInterface(const types::LeAudioCodecId& codec_id) { impl = new Impl(codec_id); + for (auto& foo : mock_life_listener_list) { + foo(impl, false); + } +} +CodecInterface::~CodecInterface() { + for (auto& foo : mock_life_listener_list) { + foo(impl, true); + } + delete impl; } -CodecInterface::~CodecInterface() { delete impl; } bool CodecInterface::IsReady() { return impl->IsReady(); }; CodecInterface::Status CodecInterface::InitEncoder( const LeAudioCodecConfiguration& pcm_config, @@ -65,3 +78,12 @@ uint8_t CodecInterface::GetNumOfBytesPerSample() { return impl->GetNumOfBytesPerSample(); }; } // namespace bluetooth::le_audio + +void MockCodecInterface::RegisterMockInstanceHook( + std::function<void(MockCodecInterface*, bool)> listener) { + mock_life_listener_list.push_back(std::move(listener)); +} + +void MockCodecInterface::ClearMockInstanceHookList() { + mock_life_listener_list.clear(); +} diff --git a/system/bta/le_audio/mock_codec_interface.h b/system/bta/le_audio/mock_codec_interface.h index 974e049779..2b3ecaa958 100644 --- a/system/bta/le_audio/mock_codec_interface.h +++ b/system/bta/le_audio/mock_codec_interface.h @@ -24,6 +24,10 @@ class MockCodecInterface { public: + static void RegisterMockInstanceHook( + std::function<void(MockCodecInterface*, bool)>); + static void ClearMockInstanceHookList(); + MockCodecInterface() = default; MockCodecInterface(const MockCodecInterface&) = delete; MockCodecInterface& operator=(const MockCodecInterface&) = delete; diff --git a/system/bta/le_audio/state_machine_test.cc b/system/bta/le_audio/state_machine_test.cc index c23083ec4d..43f08d3fed 100644 --- a/system/bta/le_audio/state_machine_test.cc +++ b/system/bta/le_audio/state_machine_test.cc @@ -140,7 +140,7 @@ constexpr uint8_t kCapTypeSupportedSamplingFrequencies = 0x01; constexpr uint8_t kCapTypeSupportedFrameDurations = 0x02; constexpr uint8_t kCapTypeAudioChannelCount = 0x03; constexpr uint8_t kCapTypeSupportedOctetsPerCodecFrame = 0x04; -// constexpr uint8_t kCapTypeSupportedLc3CodecFramesPerSdu = 0x05; +constexpr uint8_t kCapTypeSupportedLc3CodecFramesPerSdu = 0x05; // constexpr uint8_t kCapSamplingFrequency8000Hz = 0x0001; // constexpr uint8_t kCapSamplingFrequency11025Hz = 0x0002; @@ -247,6 +247,7 @@ class StateMachineTestBase : public Test { uint8_t additional_snk_ases = 0; uint8_t additional_src_ases = 0; uint8_t channel_count_ = kLeAudioCodecChannelCountSingleChannel; + uint8_t codec_frame_blocks_per_sdu_ = 1; uint16_t sample_freq_ = codec_specific::kCapSamplingFrequency16000Hz | codec_specific::kCapSamplingFrequency32000Hz; uint8_t channel_allocations_sink_ = @@ -407,6 +408,7 @@ class StateMachineTestBase : public Test { [this](uint8_t cig_id, bluetooth::hci::iso_manager::cig_create_params p) { log::debug("CreateCig"); + last_cig_params_ = p; auto& group = le_audio_device_groups_[cig_id]; if (group) { @@ -900,6 +902,7 @@ class StateMachineTestBase : public Test { uint8_t audio_channel_count_bitfield, uint16_t supported_octets_per_codec_frame_min, uint16_t supported_octets_per_codec_frame_max, + uint8_t codec_frame_blocks_per_sdu_ = 1, uint8_t coding_format = codec_specific::kLc3CodingFormat, uint16_t vendor_company_id = 0x0000, uint16_t vendor_codec_id = 0x0000, std::vector<uint8_t> metadata = {}) { @@ -921,6 +924,8 @@ class StateMachineTestBase : public Test { (uint8_t)(supported_octets_per_codec_frame_max >> 8), }}, }); + ltv_map.Add(codec_specific::kCapTypeSupportedLc3CodecFramesPerSdu, + (uint8_t)codec_frame_blocks_per_sdu_); recs.push_back({ .codec_id = { @@ -1066,7 +1071,7 @@ class StateMachineTestBase : public Test { codec_specific::kCapFrameDuration10ms | codec_specific::kCapFrameDuration7p5ms | codec_specific::kCapFrameDuration10msPreferred, - channel_count_, 30, 120); + channel_count_, 30, 120, codec_frame_blocks_per_sdu_); types::hdl_pair handle_pair; handle_pair.val_hdl = attr_handle++; @@ -1091,7 +1096,7 @@ class StateMachineTestBase : public Test { codec_specific::kCapFrameDuration10ms | codec_specific::kCapFrameDuration7p5ms | codec_specific::kCapFrameDuration10msPreferred, - 0b00000001, 30, 120); + 0b00000001, 30, 120, codec_frame_blocks_per_sdu_); types::hdl_pair handle_pair; handle_pair.val_hdl = attr_handle++; @@ -1188,7 +1193,7 @@ class StateMachineTestBase : public Test { codec_configured_state_params.framing = ascs::kAseParamFramingUnframedSupported; codec_configured_state_params.preferred_retrans_nb = 0x04; - codec_configured_state_params.max_transport_latency = 0x0010; + codec_configured_state_params.max_transport_latency = 0x0020; codec_configured_state_params.pres_delay_min = 0xABABAB; codec_configured_state_params.pres_delay_max = 0xCDCDCD; codec_configured_state_params.preferred_pres_delay_min = @@ -1605,6 +1610,7 @@ class StateMachineTestBase : public Test { gatt::MockBtaGattQueue gatt_queue; bluetooth::hci::IsoManager* iso_manager_; + bluetooth::hci::iso_manager::cig_create_params last_cig_params_; MockIsoManager* mock_iso_manager_; bluetooth::le_audio::CodecManager* codec_manager_; MockCodecManager* mock_codec_manager_; @@ -1712,6 +1718,153 @@ TEST_F(StateMachineTest, testConfigureCodecSingle) { ASSERT_EQ(0, get_func_call_count("alarm_cancel")); } +TEST_F(StateMachineTest, testConfigureCodecSingleFb2) { + codec_frame_blocks_per_sdu_ = 2; + bool is_fb2_passed_as_sink_requirement = false; + bool is_fb2_passed_as_source_requirement = false; + + ON_CALL(*mock_codec_manager_, GetCodecConfig) + .WillByDefault(Invoke([&](const bluetooth::le_audio::CodecManager:: + UnicastConfigurationRequirements& + requirements, + bluetooth::le_audio::CodecManager:: + UnicastConfigurationVerifier verifier) { + auto configs = + *bluetooth::le_audio::AudioSetConfigurationProvider::Get() + ->GetConfigurations(requirements.audio_context_type); + // Note: This dual bidir SWB exclusion logic has to match the + // CodecManager::GetCodecConfig() implementation. + if (!CodecManager::GetInstance()->IsDualBiDirSwbSupported()) { + configs.erase( + std::remove_if(configs.begin(), configs.end(), + [](auto const& el) { + if (el->confs.source.empty()) return false; + return AudioSetConfigurationProvider::Get() + ->CheckConfigurationIsDualBiDirSwb(*el); + }), + configs.end()); + } + + auto cfg = verifier(requirements, &configs); + if (cfg == nullptr) { + return std::unique_ptr< + bluetooth::le_audio::set_configurations::AudioSetConfiguration>( + nullptr); + } + auto config = *cfg; + + if (requirements.sink_pacs.has_value()) { + for (auto const& rec : requirements.sink_pacs.value()) { + auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities(); + if (caps.HasSupportedMaxCodecFramesPerSdu()) { + if (caps.supported_max_codec_frames_per_sdu.value() == + codec_frame_blocks_per_sdu_) { + // Scale by Codec Frames Per SDU = 2 + for (auto& entry : config.confs.sink) { + entry.codec.params.Add( + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, + (uint8_t)codec_frame_blocks_per_sdu_); + entry.qos.maxSdu *= codec_frame_blocks_per_sdu_; + entry.qos.sduIntervalUs *= codec_frame_blocks_per_sdu_; + entry.qos.max_transport_latency *= + codec_frame_blocks_per_sdu_; + } + is_fb2_passed_as_sink_requirement = true; + } + } + } + } + if (requirements.source_pacs.has_value()) { + for (auto const& rec : requirements.source_pacs.value()) { + auto caps = rec.codec_spec_caps.GetAsCoreCodecCapabilities(); + if (caps.HasSupportedMaxCodecFramesPerSdu()) { + if (caps.supported_max_codec_frames_per_sdu.value() == + codec_frame_blocks_per_sdu_) { + // Scale by Codec Frames Per SDU = 2 + for (auto& entry : config.confs.source) { + entry.codec.params.Add( + codec_spec_conf::kLeAudioLtvTypeCodecFrameBlocksPerSdu, + (uint8_t)codec_frame_blocks_per_sdu_); + entry.qos.maxSdu *= codec_frame_blocks_per_sdu_; + entry.qos.sduIntervalUs *= codec_frame_blocks_per_sdu_; + entry.qos.max_transport_latency *= + codec_frame_blocks_per_sdu_; + } + is_fb2_passed_as_source_requirement = true; + } + } + } + } + + return std::make_unique< + bluetooth::le_audio::set_configurations::AudioSetConfiguration>( + config); + })); + + /* Device is banded headphones with 1x snk + 0x src ase + * (1xunidirectional CIS) with channel count 2 (for stereo + */ + const auto context_type = kContextTypeRingtone; + const int leaudio_group_id = 2; + channel_count_ = kLeAudioCodecChannelCountSingleChannel | + kLeAudioCodecChannelCountTwoChannel; + + /* Prepare the fake connected device group */ + auto* group = PrepareSingleTestDeviceGroup(leaudio_group_id, context_type); + + /* Since we prepared device with Ringtone context in mind, only one ASE + * should have been configured. + */ + auto* leAudioDevice = group->GetFirstDevice(); + PrepareConfigureCodecHandler(group, 1); + + /* Start the configuration and stream Media content. + * Expect 2 times: for Codec Configure & QoS Configure */ + EXPECT_CALL(gatt_queue, + WriteCharacteristic(1, leAudioDevice->ctp_hdls_.val_hdl, _, + GATT_WRITE_NO_RSP, _, _)) + .Times(2); + + InjectInitialIdleNotification(group); + + EXPECT_CALL(*mock_iso_manager_, CreateCig).Times(1); + ASSERT_TRUE(LeAudioGroupStateMachine::Get()->StartStream( + group, context_type, + {.sink = types::AudioContexts(context_type), + .source = types::AudioContexts(context_type)})); + + /* Check if group has transitioned to a proper state */ + ASSERT_EQ(group->GetState(), + types::AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED); + + /* Cancel is called when group goes to streaming. */ + ASSERT_EQ(0, get_func_call_count("alarm_cancel")); + + ASSERT_TRUE(is_fb2_passed_as_sink_requirement); + + /* Make sure that data interval is based on the codec frame blocks count */ + auto data_interval = group->GetActiveConfiguration() + ->confs.sink.at(0) + .codec.GetDataIntervalUs(); + ASSERT_EQ(data_interval, group->GetActiveConfiguration() + ->confs.sink.at(0) + .codec.params.GetAsCoreCodecConfig() + .GetFrameDurationUs() * + codec_frame_blocks_per_sdu_); + + /* Verify CIG parameters */ + auto channel_count = group->GetActiveConfiguration() + ->confs.sink.at(0) + .codec.GetChannelCountPerIsoStream(); + auto frame_octets = group->GetActiveConfiguration() + ->confs.sink.at(0) + .codec.GetOctectsPerFrame(); + ASSERT_NE(last_cig_params_.cis_cfgs.size(), 0lu); + ASSERT_EQ(last_cig_params_.sdu_itv_mtos, data_interval); + ASSERT_EQ(last_cig_params_.cis_cfgs.at(0).max_sdu_size_mtos, + codec_frame_blocks_per_sdu_ * channel_count * frame_octets); +} + TEST_F(StateMachineTest, testConfigureCodecMulti) { const auto context_type = kContextTypeMedia; const auto leaudio_group_id = 2; diff --git a/system/btif/include/btif_av.h b/system/btif/include/btif_av.h index de97fa142f..7d4e0ca269 100644 --- a/system/btif/include/btif_av.h +++ b/system/btif/include/btif_av.h @@ -308,8 +308,6 @@ bool btif_av_is_source_enabled(void); bool btif_av_both_enable(void); bool btif_av_src_sink_coexist_enabled(void); bool btif_av_is_sink_enabled(void); -bool btif_av_is_connected_addr(const RawAddress& peer_address, - const A2dpType local_a2dp_type); bool btif_av_peer_is_connected_sink(const RawAddress& peer_address); bool btif_av_peer_is_connected_source(const RawAddress& peer_address); bool btif_av_peer_is_sink(const RawAddress& peer_address); diff --git a/system/btif/include/btif_rc.h b/system/btif/include/btif_rc.h index a78110d87e..ea2e9f9da1 100644 --- a/system/btif/include/btif_rc.h +++ b/system/btif/include/btif_rc.h @@ -27,6 +27,8 @@ uint8_t btif_rc_get_connected_peer_handle(const RawAddress& peer_addr); void btif_rc_check_handle_pending_play(const RawAddress& peer_addr, bool bSendToApp); bool btif_rc_is_connected_peer(const RawAddress& peer_addr); +void btif_rc_check_pending_cmd(const RawAddress& peer_addr); +void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr); void btif_debug_rc_dump(int fd); #endif // BTIF_RC_H diff --git a/system/btif/src/btif_av.cc b/system/btif/src/btif_av.cc index 56ff784492..a9a30a41a1 100644 --- a/system/btif/src/btif_av.cc +++ b/system/btif/src/btif_av.cc @@ -71,8 +71,8 @@ using namespace bluetooth; /***************************************************************************** * Constants & Macros *****************************************************************************/ -static const std::string kBtifAvSourceServiceName = "Advanced Audio Source"; -static const std::string kBtifAvSinkServiceName = "Advanced Audio Sink"; +static const char kBtifAvSourceServiceName[] = "Advanced Audio Source"; +static const char kBtifAvSinkServiceName[] = "Advanced Audio Sink"; static constexpr int kDefaultMaxConnectedAudioDevices = 1; static constexpr tBTA_AV_HNDL kBtaHandleUnknown = 0; @@ -161,7 +161,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine { class StateIdle : public State { public: - StateIdle(BtifAvStateMachine& sm) + explicit StateIdle(BtifAvStateMachine& sm) : State(sm, kStateIdle), peer_(sm.Peer()) {} void OnEnter() override; void OnExit() override; @@ -173,7 +173,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine { class StateOpening : public State { public: - StateOpening(BtifAvStateMachine& sm) + explicit StateOpening(BtifAvStateMachine& sm) : State(sm, kStateOpening), peer_(sm.Peer()) {} void OnEnter() override; void OnExit() override; @@ -185,7 +185,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine { class StateOpened : public State { public: - StateOpened(BtifAvStateMachine& sm) + explicit StateOpened(BtifAvStateMachine& sm) : State(sm, kStateOpened), peer_(sm.Peer()) {} void OnEnter() override; void OnExit() override; @@ -197,7 +197,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine { class StateStarted : public State { public: - StateStarted(BtifAvStateMachine& sm) + explicit StateStarted(BtifAvStateMachine& sm) : State(sm, kStateStarted), peer_(sm.Peer()) {} void OnEnter() override; void OnExit() override; @@ -209,7 +209,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine { class StateClosing : public State { public: - StateClosing(BtifAvStateMachine& sm) + explicit StateClosing(BtifAvStateMachine& sm) : State(sm, kStateClosing), peer_(sm.Peer()) {} void OnEnter() override; void OnExit() override; @@ -219,7 +219,7 @@ class BtifAvStateMachine : public bluetooth::common::StateMachine { BtifAvPeer& peer_; }; - BtifAvStateMachine(BtifAvPeer& btif_av_peer) : peer_(btif_av_peer) { + explicit BtifAvStateMachine(BtifAvPeer& btif_av_peer) : peer_(btif_av_peer) { state_idle_ = new StateIdle(*this); state_opening_ = new StateOpening(*this); state_opened_ = new StateOpened(*this); @@ -407,7 +407,7 @@ class BtifAvSource { btav_source_callbacks_t* Callbacks() { return callbacks_; } bool Enabled() const { return enabled_; } bool A2dpOffloadEnabled() const { return a2dp_offload_enabled_; } - // TODO: b/321806163: Remove this method as part of flag cleanup + // TODO(b/321806163): Remove this method as part of flag cleanup void SetInvalidPeerCheck(bool invalid_peer_check) { invalid_peer_check_ = invalid_peer_check; } @@ -651,7 +651,7 @@ class BtifAvSink { btav_sink_callbacks_t* Callbacks() { return callbacks_; } bool Enabled() const { return enabled_; } - // TODO: b/321806163: Remove this method as part of flag cleanup + // TODO(b/321806163): Remove this method as part of flag cleanup void SetInvalidPeerCheck(bool invalid_peer_check) { invalid_peer_check_ = invalid_peer_check; } @@ -839,19 +839,15 @@ static void btif_av_sink_initiate_av_open_timer_timeout(void* data); static void bta_av_sink_media_callback(const RawAddress& peer_address, tBTA_AV_EVT event, tBTA_AV_MEDIA* p_data); -extern bool btif_av_both_enable(void); -extern bool btif_av_is_connected_addr(const RawAddress& peer_address, - const A2dpType local_a2dp_type); -extern bool btif_av_peer_is_sink(const RawAddress& peer_address); -extern void btif_rc_check_pending_cmd(const RawAddress& peer_address); -extern void btif_rc_get_addr_by_handle(uint8_t handle, RawAddress& rc_addr); static BtifAvPeer* btif_av_source_find_peer(const RawAddress& peer_address) { return btif_av_source.FindPeer(peer_address); } + static BtifAvPeer* btif_av_sink_find_peer(const RawAddress& peer_address) { return btif_av_sink.FindPeer(peer_address); } + static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address, const A2dpType local_a2dp_type) { if (com::android::bluetooth::flags::a2dp_concurrent_source_sink()) { @@ -894,6 +890,7 @@ static BtifAvPeer* btif_av_find_peer(const RawAddress& peer_address, if (btif_av_sink.Enabled()) return btif_av_sink_find_peer(peer_address); return nullptr; } + static BtifAvPeer* btif_av_find_active_peer(const A2dpType local_a2dp_type) { if (com::android::bluetooth::flags::a2dp_concurrent_source_sink()) { if (btif_av_source.Enabled() && local_a2dp_type == A2dpType::kSource) @@ -943,7 +940,7 @@ const RawAddress& btif_av_find_by_handle(tBTA_AV_HNDL bta_handle) { *****************************************************************************/ const char* dump_av_sm_event_name(btif_av_sm_event_t event) { - switch ((int)event) { + switch (static_cast<int>(event)) { CASE_RETURN_STR(BTA_AV_ENABLE_EVT) CASE_RETURN_STR(BTA_AV_REGISTER_EVT) CASE_RETURN_STR(BTA_AV_OPEN_EVT) @@ -1034,15 +1031,17 @@ void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data, log::assert_that(data_length >= sizeof(tBTA_AV), "assert failed: data_length >= sizeof(tBTA_AV)"); const tBTA_AV* av_src = (const tBTA_AV*)p_data; - tBTA_AV* av_dest = (tBTA_AV*)data_; + tBTA_AV* av_dest = reinterpret_cast<tBTA_AV*>(data_); if (av_src->meta_msg.p_data && av_src->meta_msg.len) { - av_dest->meta_msg.p_data = (uint8_t*)osi_calloc(av_src->meta_msg.len); + av_dest->meta_msg.p_data = + reinterpret_cast<uint8_t*>(osi_calloc(av_src->meta_msg.len)); memcpy(av_dest->meta_msg.p_data, av_src->meta_msg.p_data, av_src->meta_msg.len); } if (av_src->meta_msg.p_msg) { - av_dest->meta_msg.p_msg = (tAVRC_MSG*)osi_calloc(sizeof(tAVRC_MSG)); + av_dest->meta_msg.p_msg = + reinterpret_cast<tAVRC_MSG*>(osi_calloc(sizeof(tAVRC_MSG))); memcpy(av_dest->meta_msg.p_msg, av_src->meta_msg.p_msg, sizeof(tAVRC_MSG)); @@ -1051,15 +1050,15 @@ void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data, if ((p_msg_src->hdr.opcode == AVRC_OP_VENDOR) && (p_msg_src->vendor.p_vendor_data && p_msg_src->vendor.vendor_len)) { - p_msg_dest->vendor.p_vendor_data = - (uint8_t*)osi_calloc(p_msg_src->vendor.vendor_len); + p_msg_dest->vendor.p_vendor_data = reinterpret_cast<uint8_t*>( + osi_calloc(p_msg_src->vendor.vendor_len)); memcpy(p_msg_dest->vendor.p_vendor_data, p_msg_src->vendor.p_vendor_data, p_msg_src->vendor.vendor_len); } if ((p_msg_src->hdr.opcode == AVRC_OP_BROWSE) && p_msg_src->browse.p_browse_data && p_msg_src->browse.browse_len) { - p_msg_dest->browse.p_browse_data = - (uint8_t*)osi_calloc(p_msg_src->browse.browse_len); + p_msg_dest->browse.p_browse_data = reinterpret_cast<uint8_t*>( + osi_calloc(p_msg_src->browse.browse_len)); memcpy(p_msg_dest->browse.p_browse_data, p_msg_src->browse.p_browse_data, p_msg_src->browse.browse_len); } @@ -1074,8 +1073,9 @@ void BtifAvEvent::DeepCopy(uint32_t event, const void* p_data, void BtifAvEvent::DeepFree() { switch (event_) { case BTA_AV_META_MSG_EVT: { - tBTA_AV* av = (tBTA_AV*)data_; - osi_free_and_reset((void**)&av->meta_msg.p_data); + tBTA_AV* av = reinterpret_cast<tBTA_AV*>(data_); + osi_free(av->meta_msg.p_data); + av->meta_msg.p_data = nullptr; if (av->meta_msg.p_msg) { if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_VENDOR) { @@ -1084,7 +1084,8 @@ void BtifAvEvent::DeepFree() { if (av->meta_msg.p_msg->hdr.opcode == AVRC_OP_BROWSE) { osi_free(av->meta_msg.p_msg->browse.p_browse_data); } - osi_free_and_reset((void**)&av->meta_msg.p_msg); + osi_free(av->meta_msg.p_msg); + av->meta_msg.p_msg = nullptr; } } break; @@ -1092,7 +1093,8 @@ void BtifAvEvent::DeepFree() { break; } - osi_free_and_reset((void**)&data_); + osi_free(data_); + data_ = nullptr; data_length_ = 0; } @@ -1396,7 +1398,7 @@ void BtifAvSource::DispatchSuspendStreamEvent(btif_av_sm_event_t event) { if (event != BTIF_AV_SUSPEND_STREAM_REQ_EVT && event != BTIF_AV_STOP_STREAM_REQ_EVT) { log::error("Invalid event: {} id: {}", dump_av_sm_event_name(event), - (int)event); + static_cast<int>(event)); return; } bool av_stream_idle = true; @@ -1442,7 +1444,7 @@ void BtifAvSource::CleanupAllPeers() { void BtifAvSource::RegisterAllBtaHandles() { for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) { - BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSourceServiceName.c_str(), peer_id, + BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSourceServiceName, peer_id, nullptr, UUID_SERVCLASS_AUDIO_SOURCE); } } @@ -1718,7 +1720,7 @@ void BtifAvSink::CleanupAllPeers() { void BtifAvSink::RegisterAllBtaHandles() { for (int peer_id = kPeerIdMin; peer_id < kPeerIdMax; peer_id++) { - BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSinkServiceName.c_str(), peer_id, + BTA_AvRegister(BTA_AV_CHNL_AUDIO, kBtifAvSinkServiceName, peer_id, bta_av_sink_media_callback, UUID_SERVCLASS_AUDIO_SINK); } } @@ -1894,7 +1896,8 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { log::error("Source profile doesn't allow connection to peer:{}", peer_.PeerAddress()); if (btif_av_src_sink_coexist_enabled()) - BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle); + BTA_AvCloseRc( + (reinterpret_cast<tBTA_AV*>(p_data))->rc_open.rc_handle); else btif_av_source_disconnect(peer_.PeerAddress()); } @@ -1904,7 +1907,8 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { log::error("Sink profile doesn't allow connection to peer:{}", peer_.PeerAddress()); if (btif_av_src_sink_coexist_enabled()) - BTA_AvCloseRc(((tBTA_AV*)p_data)->rc_open.rc_handle); + BTA_AvCloseRc( + (reinterpret_cast<tBTA_AV*>(p_data))->rc_open.rc_handle); else btif_av_sink_disconnect(peer_.PeerAddress()); } @@ -1937,12 +1941,12 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { } } if (event == BTA_AV_RC_OPEN_EVT) { - btif_rc_handler(event, (tBTA_AV*)p_data); + btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data)); } } break; case BTA_AV_RC_BROWSE_OPEN_EVT: - btif_rc_handler(event, (tBTA_AV*)p_data); + btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data)); break; // In case Signalling channel is not down and remote started Streaming @@ -1957,7 +1961,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { } break; case BTA_AV_OPEN_EVT: { - tBTA_AV* p_bta_data = (tBTA_AV*)p_data; + tBTA_AV* p_bta_data = reinterpret_cast<tBTA_AV*>(p_data); tBTA_AV_STATUS status = p_bta_data->open.status; bool can_connect = true; @@ -2070,7 +2074,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { case BTA_AV_RC_FEAT_EVT: case BTA_AV_RC_PSM_EVT: case BTA_AV_REMOTE_RSP_EVT: - btif_rc_handler(event, (tBTA_AV*)p_data); + btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data)); break; case BTIF_AV_AVRCP_CLOSE_EVT: @@ -2080,7 +2084,7 @@ bool BtifAvStateMachine::StateIdle::ProcessEvent(uint32_t event, void* p_data) { alarm_cancel(peer_.AvOpenOnRcTimer()); if (event == BTA_AV_RC_CLOSE_EVT) { - btif_rc_handler(event, (tBTA_AV*)p_data); + btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data)); } } break; @@ -2164,7 +2168,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, break; case BTA_AV_OPEN_EVT: { - tBTA_AV* p_bta_data = (tBTA_AV*)p_data; + tBTA_AV* p_bta_data = reinterpret_cast<tBTA_AV*>(p_data); int av_state; tBTA_AV_STATUS status = p_bta_data->open.status; @@ -2372,7 +2376,7 @@ bool BtifAvStateMachine::StateOpening::ProcessEvent(uint32_t event, } break; - CHECK_RC_EVENT(event, (tBTA_AV*)p_data); + CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data)); default: log_counter_metrics_btif(android::bluetooth::CodePathCounterKeyEnum:: @@ -2414,7 +2418,7 @@ void BtifAvStateMachine::StateOpened::OnExit() { bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, void* p_data) { - tBTA_AV* p_av = (tBTA_AV*)p_data; + tBTA_AV* p_av = reinterpret_cast<tBTA_AV*>(p_data); log::info("state=Opened peer={} event={} flags={} active_peer={}", peer_.PeerAddress(), BtifAvEvent::EventName(event), @@ -2434,6 +2438,9 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, case BTIF_AV_ACL_DISCONNECTED: break; // Ignore + // Event sent by the Bluetooth Audio HAL to a source A2DP stack + // when a stream is ready to play. The stack shall send AVDTP Start to the + // remote device to start the stream. case BTIF_AV_START_STREAM_REQ_EVT: { log::info("Peer {} : event={} flags={}", peer_.PeerAddress(), BtifAvEvent::EventName(event), peer_.FlagsToString()); @@ -2449,6 +2456,10 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, peer_.SetFlags(BtifAvPeer::kFlagPendingStart); } break; + // Event sent by lower layer to indicate that the AVDTP stream is started. + // May be initiated by the remote device to start a stream, in this case the + // event is ignored by source A2DP, and the stack shall immediately suspend + // the stream. case BTA_AV_START_EVT: { log::info( "Peer {} : event={} status={} suspending={} initiator={} flags={}", @@ -2475,13 +2486,14 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, should_suspend = true; } - // If peer is A2DP Source, do ACK commands to audio HAL and start - // media task - if (btif_a2dp_on_started( - peer_.PeerAddress(), &p_av->start, - peer_.IsSource() ? A2dpType::kSink : A2dpType::kSource)) { - // Only clear pending flag after acknowledgement - peer_.ClearFlags(BtifAvPeer::kFlagPendingStart); + // Invoke the started handler only when initiator. + if (!com::android::bluetooth::flags::a2dp_ignore_started_when_responder() || + peer_.CheckFlags(BtifAvPeer::kFlagPendingStart)) { + if (btif_a2dp_on_started( + peer_.PeerAddress(), &p_av->start, A2dpType::kSource)) { + // Only clear pending flag after acknowledgement + peer_.ClearFlags(BtifAvPeer::kFlagPendingStart); + } } } @@ -2499,8 +2511,8 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, BTIF_AV_SUSPEND_STREAM_REQ_EVT); } peer_.StateMachine().TransitionTo(BtifAvStateMachine::kStateStarted); - - } break; + break; + } case BTIF_AV_DISCONNECT_REQ_EVT: BTA_AvClose(peer_.BtaHandle()); @@ -2604,7 +2616,7 @@ bool BtifAvStateMachine::StateOpened::ProcessEvent(uint32_t event, } break; - CHECK_RC_EVENT(event, (tBTA_AV*)p_data); + CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data)); case BTIF_AV_SET_LATENCY_REQ_EVT: { const btif_av_set_latency_req_t* p_set_latency_req = @@ -2645,7 +2657,7 @@ void BtifAvStateMachine::StateStarted::OnExit() { bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event, void* p_data) { - tBTA_AV* p_av = (tBTA_AV*)p_data; + tBTA_AV* p_av = reinterpret_cast<tBTA_AV*>(p_data); log::info("state=Started peer={} event={} flags={} active_peer={}", peer_.PeerAddress(), BtifAvEvent::EventName(event), @@ -2848,7 +2860,7 @@ bool BtifAvStateMachine::StateStarted::ProcessEvent(uint32_t event, BTA_AvSetLatency(peer_.BtaHandle(), p_set_latency_req->is_low_latency); } break; - CHECK_RC_EVENT(event, (tBTA_AV*)p_data); + CHECK_RC_EVENT(event, reinterpret_cast<tBTA_AV*>(p_data)); default: log::warn("Peer {} : Unhandled event={}", peer_.PeerAddress(), @@ -2908,12 +2920,12 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event, // Handle the RC_CLOSE event for the cleanup case BTA_AV_RC_CLOSE_EVT: - btif_rc_handler(event, (tBTA_AV*)p_data); + btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data)); break; // Handle the RC_BROWSE_CLOSE event for testing case BTA_AV_RC_BROWSE_CLOSE_EVT: - btif_rc_handler(event, (tBTA_AV*)p_data); + btif_rc_handler(event, reinterpret_cast<tBTA_AV*>(p_data)); break; case BTIF_AV_OFFLOAD_START_REQ_EVT: @@ -2943,7 +2955,7 @@ bool BtifAvStateMachine::StateClosing::ProcessEvent(uint32_t event, * interoperate with headsets that do establish AV after AVRCP connection. */ static void btif_av_source_initiate_av_open_timer_timeout(void* data) { - BtifAvPeer* peer = (BtifAvPeer*)data; + BtifAvPeer* peer = reinterpret_cast<BtifAvPeer*>(data); bool device_connected = false; if (com::android::bluetooth::flags::avrcp_connect_a2dp_delayed() && @@ -2980,7 +2992,7 @@ static void btif_av_source_initiate_av_open_timer_timeout(void* data) { * establishes AVRCP connection without AV connection. */ static void btif_av_sink_initiate_av_open_timer_timeout(void* data) { - BtifAvPeer* peer = (BtifAvPeer*)data; + BtifAvPeer* peer = reinterpret_cast<BtifAvPeer*>(data); log::verbose("Peer {}", peer->PeerAddress()); @@ -3296,7 +3308,7 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, RawAddress peer_address = RawAddress::kEmpty; tBTA_AV_HNDL bta_handle = kBtaHandleUnknown; tBTA_AV_EVT event = btif_av_event.Event(); - tBTA_AV* p_data = (tBTA_AV*)btif_av_event.Data(); + tBTA_AV* p_data = reinterpret_cast<tBTA_AV*>(btif_av_event.Data()); std::string msg; log::verbose("peer_sep={} event={}", peer_stream_endpoint_text(peer_sep), @@ -3406,8 +3418,9 @@ static void btif_av_handle_bta_av_event(uint8_t peer_sep, peer_address = btif_av_sink.ActivePeer(); } break; - } else + } else { FALLTHROUGH_INTENDED; + } } case BTA_AV_OFFLOAD_START_RSP_EVT: { // TODO: Might be wrong - this code will be removed once those @@ -3530,7 +3543,8 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address, int state = peer->StateMachine().StateId(); if ((state == BtifAvStateMachine::kStateStarted) || (state == BtifAvStateMachine::kStateOpened)) { - uint8_t queue_len = btif_a2dp_sink_enqueue_buf((BT_HDR*)p_data); + uint8_t queue_len = + btif_a2dp_sink_enqueue_buf(reinterpret_cast<BT_HDR*>(p_data)); log::verbose("Packets in Sink queue {}", queue_len); } } @@ -3542,7 +3556,8 @@ static void bta_av_sink_media_callback(const RawAddress& peer_address, log::verbose("address={}", p_data->avk_config.bd_addr); // Update the codec info of the A2DP Sink decoder - btif_a2dp_sink_update_decoder((uint8_t*)(p_data->avk_config.codec_info)); + btif_a2dp_sink_update_decoder( + reinterpret_cast<uint8_t*>(p_data->avk_config.codec_info)); config_req.sample_rate = A2DP_GetTrackSampleRate(p_data->avk_config.codec_info); diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc index 4778c9403c..34f027a676 100644 --- a/system/btif/src/btif_dm.cc +++ b/system/btif/src/btif_dm.cc @@ -854,20 +854,7 @@ static void btif_dm_cb_create_bond(const RawAddress bd_addr, static_cast<tBT_DEVICE_TYPE>(device_type)); } - if (!com::android::bluetooth::flags::connect_hid_after_service_discovery() && - is_hid && (device_type & BT_DEVICE_TYPE_BLE) == 0) { - tAclLinkSpec link_spec; - link_spec.addrt.bda = bd_addr; - link_spec.addrt.type = addr_type; - link_spec.transport = transport; - const bt_status_t status = - GetInterfaceToProfiles()->profileSpecific_HACK->btif_hh_connect( - link_spec); - if (status != BT_STATUS_SUCCESS) - bond_state_changed(status, bd_addr, BT_BOND_STATE_NONE); - } else { - BTA_DmBond(bd_addr, addr_type, transport, device_type); - } + BTA_DmBond(bd_addr, addr_type, transport, device_type); /* Track originator of bond creation */ pairing_cb.is_local_initiated = true; } @@ -1658,27 +1645,8 @@ static bool btif_should_ignore_uuid(const Uuid& uuid) { } static bool btif_is_gatt_service_discovery_post_pairing(const RawAddress bd_addr) { - if (!com::android::bluetooth::flags:: - reset_pairing_only_for_related_service_discovery()) { - if (bd_addr == pairing_cb.bd_addr || bd_addr == pairing_cb.static_bdaddr) { - if (pairing_cb.gatt_over_le != - btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED) { - log::error( - "gatt_over_le should be SCHEDULED, did someone clear the control " - "block for {} ?", - bd_addr); - } - - return true; - } - - return false; - } - - return ((bd_addr == pairing_cb.bd_addr || - bd_addr == pairing_cb.static_bdaddr) && - (pairing_cb.gatt_over_le == - btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED)); + return (bd_addr == pairing_cb.bd_addr || bd_addr == pairing_cb.static_bdaddr) && + (pairing_cb.gatt_over_le == btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED); } static void btif_merge_existing_uuids(RawAddress& addr, std::set<Uuid>* uuids) { @@ -1716,11 +1684,7 @@ static void btif_on_service_discovery_results( if (pairing_cb.sdp_attempts) { log::warn("SDP failed after bonding re-attempting for {}", bd_addr); pairing_cb.sdp_attempts++; - if (com::android::bluetooth::flags::force_bredr_for_sdp_retry()) { - btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_BR_EDR); - } else { - btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_AUTO); - } + btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_BR_EDR); } else { log::warn("SDP triggered by someone failed when bonding"); } @@ -3493,10 +3457,6 @@ static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF* p_ssp_key_notif) { static bool btif_dm_ble_is_temp_pairing(RawAddress& bd_addr, bool ctkd) { if (btm_get_bond_type_dev(bd_addr) == BOND_TYPE_TEMPORARY) { - if (!com::android::bluetooth::flags::ignore_bond_type_for_le()) { - return true; - } - return ctkd; } diff --git a/system/gd/rust/linux/stack/src/bluetooth_media.rs b/system/gd/rust/linux/stack/src/bluetooth_media.rs index 6275fc5aec..a3f9eb19a2 100644 --- a/system/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/system/gd/rust/linux/stack/src/bluetooth_media.rs @@ -1254,6 +1254,12 @@ impl BluetoothMedia { BtavConnectionState::Disconnected => { info!("[{}]: a2dp disconnected.", DisplayAddress(&addr)); + if self.a2dp_audio_connection_listener.is_some() { + let listener = self.a2dp_audio_connection_listener.take().unwrap(); + let data: Vec<u8> = vec![0]; + self.write_data_to_listener(listener, data); + } + self.a2dp_states.remove(&addr); self.a2dp_caps.remove(&addr); self.a2dp_audio_state.remove(&addr); @@ -1484,6 +1490,13 @@ impl BluetoothMedia { } BthfConnectionState::Disconnected => { info!("[{}]: hfp disconnected.", DisplayAddress(&addr)); + + if self.hfp_audio_connection_listener.is_some() { + let listener = self.hfp_audio_connection_listener.take().unwrap(); + let data: Vec<u8> = vec![0]; + self.write_data_to_listener(listener, data); + } + self.uhid_destroy(&addr); self.hfp_states.remove(&addr); self.hfp_cap.remove(&addr); @@ -3047,14 +3060,8 @@ impl BluetoothMedia { return; } - self.call_list.push(CallInfo { - index: 1, - dir_incoming: false, - state: CallState::Active, - number: "".into(), - }); - self.phone_state.num_active = 1; - self.phone_state_change("".into()); + self.dialing_call_impl("".into(), None); + self.answer_call_impl(); } pub fn get_group_devices(&self, group_id: i32) -> HashSet<RawAddress> { diff --git a/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc b/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc index b97015f5fa..5c1103d12c 100644 --- a/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc +++ b/system/gd/rust/topshim/btav_sink/btav_sink_shim.cc @@ -18,8 +18,8 @@ #include <memory> -#include "include/hardware/bluetooth.h" #include "btif/include/btif_av.h" +#include "include/hardware/bluetooth.h" #include "rust/cxx.h" #include "src/profiles/a2dp.rs.h" #include "types/raw_address.h" diff --git a/system/log/src/vlog_android.cc b/system/log/src/vlog_android.cc index a0c5b1bff4..e6bb2006a5 100644 --- a/system/log/src/vlog_android.cc +++ b/system/log/src/vlog_android.cc @@ -29,8 +29,7 @@ static constexpr size_t kBufferSize = 1024; void vlog(Level level, char const* tag, source_location location, fmt::string_view fmt, fmt::format_args vargs) { // Check if log is enabled. - if (!__android_log_is_loggable(level, tag, ANDROID_LOG_INFO) && - !__android_log_is_loggable(level, "bluetooth", ANDROID_LOG_INFO)) { + if (!__android_log_is_loggable(level, "bluetooth", ANDROID_LOG_INFO)) { return; } diff --git a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc index cf30d98cd9..32de722326 100644 --- a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc +++ b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc @@ -1,77 +1,239 @@ -#include <cstddef> -#include <cstdint> +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ -#include "avrcp_packet.h" #include "device.h" +#include "fuzzer/FuzzedDataProvider.h" #include "internal_include/stack_config.h" #include "packet_test_helper.h" -#include "stack/include/a2dp_api.h" -#include "types/raw_address.h" +#include "pass_through_packet.h" bool btif_av_src_sink_coexist_enabled(void) { return true; } namespace bluetooth { namespace avrcp { + +static uint32_t kMinSize = 0; +static uint32_t kMaxSize = 10; +static uint32_t kMaxLen = 100; +static uint8_t kMinScope = 0; +static uint8_t kMaxScope = 3; +static uint8_t kMediaOpId = 0x44; +static uint8_t kMask = 0xFF; +static uint8_t k8BitShift = 8; + +const Opcode kValidOpCodes[] = {Opcode::VENDOR, Opcode::UNIT_INFO, + Opcode::SUBUNIT_INFO, Opcode::PASS_THROUGH}; + +const CType kValidCTypes[] = { + CType::CONTROL, CType::STATUS, CType::NOTIFY, + CType::NOT_IMPLEMENTED, CType::ACCEPTED, CType::REJECTED, + CType::STABLE, CType::CHANGED, CType::INTERIM}; + +const BrowsePdu kPduVal[] = {BrowsePdu::SET_BROWSED_PLAYER, + BrowsePdu::GET_FOLDER_ITEMS, + BrowsePdu::CHANGE_PATH, + BrowsePdu::GET_ITEM_ATTRIBUTES, + BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS, + BrowsePdu::GENERAL_REJECT}; + +const CommandPdu kCommandPduVal[] = { + CommandPdu::GET_CAPABILITIES, + CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES, + CommandPdu::LIST_PLAYER_APPLICATION_SETTING_VALUES, + CommandPdu::GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE, + CommandPdu::SET_PLAYER_APPLICATION_SETTING_VALUE, + CommandPdu::GET_ELEMENT_ATTRIBUTES, + CommandPdu::GET_PLAY_STATUS, + CommandPdu::REGISTER_NOTIFICATION, + CommandPdu::SET_ABSOLUTE_VOLUME, + CommandPdu::SET_ADDRESSED_PLAYER, + CommandPdu::PLAY_ITEM}; + class FakeMediaInterface : public MediaInterface { public: - virtual void SendKeyEvent(uint8_t key, KeyState state) {} + FakeMediaInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {} + void SendKeyEvent(uint8_t /* key */, KeyState /* state */) { return; } using SongInfoCallback = base::Callback<void(SongInfo)>; - virtual void GetSongInfo(SongInfoCallback info_cb) {} + void GetSongInfo(SongInfoCallback info_cb) { + SongInfo sInfo; + sInfo.media_id = mFdp->ConsumeRandomLengthString(kMaxLen); + sInfo.attributes.insert(AttributeEntry( + Attribute(mFdp->ConsumeIntegralInRange<uint8_t>( + uint8_t(Attribute::TITLE), uint8_t(Attribute::DEFAULT_COVER_ART))), + mFdp->ConsumeRandomLengthString(kMaxLen))); + info_cb.Run(sInfo); + return; + } using PlayStatusCallback = base::Callback<void(PlayStatus)>; - virtual void GetPlayStatus(PlayStatusCallback status_cb) {} + void GetPlayStatus(PlayStatusCallback status_cb) { + PlayStatus pst; + status_cb.Run(pst); + return; + } using NowPlayingCallback = base::Callback<void(std::string, std::vector<SongInfo>)>; - virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) {} + void GetNowPlayingList(NowPlayingCallback now_playing_cb) { + std::string currentSongId = mFdp->ConsumeRandomLengthString(kMaxLen); + size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize); + std::vector<SongInfo> songInfoVec; + for (size_t iter = 0; iter < size; ++iter) { + SongInfo tempSongInfo; + tempSongInfo.media_id = mFdp->ConsumeRandomLengthString(kMaxLen); + tempSongInfo.attributes.insert( + AttributeEntry(Attribute(mFdp->ConsumeIntegralInRange<uint8_t>( + uint8_t(Attribute::TITLE), + uint8_t(Attribute::DEFAULT_COVER_ART))), + mFdp->ConsumeRandomLengthString(kMaxLen))); + songInfoVec.push_back(tempSongInfo); + } + now_playing_cb.Run(currentSongId, songInfoVec); + return; + } using MediaListCallback = base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>; - virtual void GetMediaPlayerList(MediaListCallback list_cb) {} + void GetMediaPlayerList(MediaListCallback list_cb) { + uint16_t currentPlayer = mFdp->ConsumeIntegral<uint16_t>(); + size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize); + std::vector<MediaPlayerInfo> playerList; + for (size_t iter = 0; iter < size; ++iter) { + MediaPlayerInfo tempInfo; + tempInfo.id = mFdp->ConsumeIntegral<uint16_t>(); + tempInfo.name = mFdp->ConsumeRandomLengthString(kMaxLen); + tempInfo.browsing_supported = mFdp->ConsumeBool(); + playerList.push_back(tempInfo); + } + list_cb.Run(currentPlayer, playerList); + return; + } using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>; - virtual void GetFolderItems(uint16_t player_id, std::string media_id, - FolderItemsCallback folder_cb) {} + void GetFolderItems(uint16_t /* player_id */, std::string /* media_id */, + FolderItemsCallback folder_cb) { + size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize); + std::vector<ListItem> list; + for (size_t iter = 0; iter < size; ++iter) { + ListItem tempList; + tempList.type = mFdp->ConsumeBool() ? ListItem::FOLDER : ListItem::SONG; + tempList.folder.media_id = mFdp->ConsumeRandomLengthString(kMaxLen); + tempList.folder.name = mFdp->ConsumeRandomLengthString(kMaxLen); + tempList.folder.is_playable = mFdp->ConsumeBool(); + tempList.song.media_id = mFdp->ConsumeRandomLengthString(kMaxLen); + tempList.song.attributes.insert( + AttributeEntry(Attribute(mFdp->ConsumeIntegralInRange<uint8_t>( + uint8_t(Attribute::TITLE), + uint8_t(Attribute::DEFAULT_COVER_ART))), + mFdp->ConsumeRandomLengthString(kMaxLen))); + list.push_back(tempList); + } + folder_cb.Run(list); + } using SetBrowsedPlayerCallback = base::Callback<void( bool success, std::string root_id, uint32_t num_items)>; - virtual void SetBrowsedPlayer(uint16_t player_id, - SetBrowsedPlayerCallback browse_cb) {} - virtual void PlayItem(uint16_t player_id, bool now_playing, - std::string media_id) {} - virtual void SetActiveDevice(const RawAddress& address) {} - virtual void RegisterUpdateCallback(MediaCallbacks* callback) {} - virtual void UnregisterUpdateCallback(MediaCallbacks* callback) {} + void SetBrowsedPlayer(uint16_t player_id, + SetBrowsedPlayerCallback browse_cb) { + std::string rootId = mFdp->ConsumeRandomLengthString(kMaxLen); + uint32_t numItems = mFdp->ConsumeIntegral<uint32_t>(); + browse_cb.Run(player_id, rootId, numItems); + return; + } + void PlayItem(uint16_t /* player_id */, bool /* now_playing */, + std::string /* media_id */) { + return; + } + void SetActiveDevice(const RawAddress& /* address */) { return; } + void RegisterUpdateCallback(MediaCallbacks* /* callback */) { return; } + void UnregisterUpdateCallback(MediaCallbacks* /* callback */) { return; } + + private: + FuzzedDataProvider* mFdp; }; class FakeVolumeInterface : public VolumeInterface { public: - virtual void DeviceConnected(const RawAddress& bdaddr) {} - virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) {} - virtual void DeviceDisconnected(const RawAddress& bdaddr) {} - virtual void SetVolume(int8_t volume) {} + FakeVolumeInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {} + void DeviceConnected(const RawAddress& /* bdaddr */) { return; } + void DeviceConnected(const RawAddress& /* bdaddr */, VolumeChangedCb cb) { + uint8_t volume = mFdp->ConsumeIntegral<uint8_t>(); + cb.Run(volume); + return; + } + void DeviceDisconnected(const RawAddress& /* bdaddr */) { return; } + void SetVolume(int8_t /* volume */) { return; } + + private: + FuzzedDataProvider* mFdp; }; class FakePlayerSettingsInterface : public PlayerSettingsInterface { public: - virtual void ListPlayerSettings(ListPlayerSettingsCallback cb) {} - virtual void ListPlayerSettingValues(PlayerAttribute setting, - ListPlayerSettingValuesCallback cb) {} - virtual void GetCurrentPlayerSettingValue( - std::vector<PlayerAttribute> attributes, - GetCurrentPlayerSettingValueCallback cb) {} - virtual void SetPlayerSettings(std::vector<PlayerAttribute> attributes, - std::vector<uint8_t> values, - SetPlayerSettingValueCallback cb) {} + FakePlayerSettingsInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {} + void ListPlayerSettings(ListPlayerSettingsCallback cb) { + uint8_t label = mFdp->ConsumeIntegral<uint8_t>(); + size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize); + std::vector<PlayerAttribute> attributes; + for (size_t iter = 0; iter < size; ++iter) { + PlayerAttribute playerAttr = + (PlayerAttribute)mFdp->ConsumeIntegralInRange<uint8_t>( + uint8_t(PlayerAttribute::EQUALIZER), + uint8_t(PlayerAttribute::SCAN)); + attributes.push_back(playerAttr); + } + cb.Run(attributes); + return; + } + void ListPlayerSettingValues(PlayerAttribute setting, + ListPlayerSettingValuesCallback cb) { + size_t size = mFdp->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); + std::vector<uint8_t> values = mFdp->ConsumeBytes<uint8_t>(size); + cb.Run(setting, values); + return; + } + void GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes, + GetCurrentPlayerSettingValueCallback cb) { + std::vector<uint8_t> values(attributes.size()); + for (size_t iter = 0; iter < attributes.size(); ++iter) { + values.push_back(mFdp->ConsumeIntegral<uint8_t>()); + } + cb.Run(attributes, values); + return; + } + void SetPlayerSettings(std::vector<PlayerAttribute> /* attributes */, + std::vector<uint8_t> /* values */, + SetPlayerSettingValueCallback cb) { + bool success = mFdp->ConsumeBool(); + cb.Run(success); + return; + } + + private: + FuzzedDataProvider* mFdp; }; class FakeA2dpInterface : public A2dpInterface { public: - virtual RawAddress active_peer() { return RawAddress(); } - virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) { + RawAddress active_peer() { return RawAddress::kAny; } + bool is_peer_in_silence_mode(const RawAddress& /* peer_address */) { return false; } - virtual void connect_audio_sink_delayed(uint8_t handle, - const RawAddress& peer_address) { + void connect_audio_sink_delayed(uint8_t /* handle */, + const RawAddress& /* peer_address */) { return; } - virtual uint16_t find_audio_sink_service(const RawAddress& peer_address, - tA2DP_FIND_CBACK p_cback) override { + uint16_t find_audio_sink_service(const RawAddress& /* peer_address */, + tA2DP_FIND_CBACK /* p_cback */) override { return 0; } }; @@ -103,25 +265,124 @@ const stack_config_t interface = {get_pts_avrcp_test, void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {} -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { - FakeMediaInterface fmi; - FakeVolumeInterface fvi; +class AVRCPDeviceFuzzer { + public: + AVRCPDeviceFuzzer(const uint8_t* Data, size_t Size) : mFdp(Data, Size) {} + void Process(); + + private: + void CreateBrowsePacket(std::vector<uint8_t>& packet); + void CreateAvrcpPacket(std::vector<uint8_t>& packet); + FuzzedDataProvider mFdp; +}; + +void AVRCPDeviceFuzzer::CreateBrowsePacket(std::vector<uint8_t>& packet) { + // Used to consume a maximum of 50% of the data to create packet. + // This ensures that we don't completely exhaust data and use the rest 50% for + // fuzzing of APIs. + packet = mFdp.ConsumeBytes<uint8_t>(mFdp.ConsumeIntegralInRange<size_t>( + 0, mFdp.remaining_bytes() * 50 / 100)); + + if (packet.size() < Packet::kMinSize()) { + packet.resize(Packet::kMinSize()); + } + packet[0] = (uint8_t)mFdp.PickValueInArray(kPduVal); + // Set packet[1] and packet[2] to corresponding value of little endian + uint16_t size = packet.size() - BrowsePacket::kMinSize(); + packet[1] = (size >> k8BitShift) & kMask; + packet[2] = size & kMask; +} + +void AVRCPDeviceFuzzer::CreateAvrcpPacket(std::vector<uint8_t>& packet) { + // Used to consume a maximum of 50% of the data to create packet. + // This ensures that we don't completely exhaust data and use the rest 50% for + // fuzzing of APIs. + packet = mFdp.ConsumeBytes<uint8_t>(mFdp.ConsumeIntegralInRange<size_t>( + 0, mFdp.remaining_bytes() * 50 / 100)); + if (packet.size() < Packet::kMinSize()) { + packet.resize(Packet::kMinSize()); + } + packet[0] = (uint8_t)mFdp.PickValueInArray(kValidCTypes); + packet[2] = (uint8_t)mFdp.PickValueInArray(kValidOpCodes); + if (packet[2] == uint8_t(Opcode::PASS_THROUGH)) { + packet.resize(PassThroughPacket::kMinSize()); + packet[3] = + mFdp.ConsumeBool() ? kMediaOpId : mFdp.ConsumeIntegral<uint8_t>(); + } else if (packet[2] == uint8_t(Opcode::VENDOR)) { + if (packet.size() <= VendorPacket::kMinSize()) { + packet.resize(VendorPacket::kMinSize() + 1); + } + packet[3] = mFdp.ConsumeIntegralInRange<uint8_t>(kMinScope, kMaxScope); + packet[5] = (uint8_t)mFdp.ConsumeBool(); // Direction + packet[6] = (uint8_t)mFdp.PickValueInArray(kCommandPduVal); + // Set packet[8] and packet[9] to corresponding value of little endian + uint16_t size = packet.size() - VendorPacket::kMinSize(); + packet[8] = (size >> k8BitShift) & kMask; + packet[9] = size & kMask; + } +} +void AVRCPDeviceFuzzer::Process() { + FakeMediaInterface fmi(&mFdp); + FakeVolumeInterface fvi(&mFdp); FakeA2dpInterface fai; - FakePlayerSettingsInterface fpsi; + FakePlayerSettingsInterface fpsi(&mFdp); - std::vector<uint8_t> Packet(Data, Data + Size); Device device( - RawAddress::kAny, true, + RawAddress::kAny /* bdaddr */, + mFdp.ConsumeBool() /* avrcp13_compatibility */, base::BindRepeating( - [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}), - 0xFFFF, 0xFFFF); + [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) { + }) /* send_msg_cb */, + mFdp.ConsumeIntegral<uint16_t>() /* ctrl_mtu */, + mFdp.ConsumeIntegral<uint16_t>() /* browse_mtu */); + device.RegisterInterfaces(&fmi, &fai, &fvi, &fpsi); - auto browse_request = TestPacketType<BrowsePacket>::Make(Packet); - device.BrowseMessageReceived(1, browse_request); + while (mFdp.remaining_bytes()) { + auto invokeAVRCP = mFdp.PickValueInArray<const std::function<void()>>({ + [&]() { + device.SetBrowseMtu( + mFdp.ConsumeIntegral<uint16_t>() /* browse_mtu */); + }, + [&]() { + device.SetBipClientStatus(mFdp.ConsumeBool() /* connected */); + }, + [&]() { + std::vector<uint8_t> browse_packet; + CreateBrowsePacket(browse_packet); + auto browse_request = + TestPacketType<BrowsePacket>::Make(browse_packet); + device.BrowseMessageReceived( + mFdp.ConsumeIntegral<uint8_t>() /* label */, browse_request); + }, + [&]() { + /* Crafting PassThroughPacket Packets */ + std::vector<uint8_t> avrcp_packet; + CreateAvrcpPacket(avrcp_packet); + auto avrcp_request = + TestPacketType<avrcp::Packet>::Make(avrcp_packet); + device.MessageReceived(mFdp.ConsumeIntegral<uint8_t>() /* label */, + avrcp_request); + }, + [&]() { + device.SendMediaUpdate(mFdp.ConsumeBool() /* metadata */, + mFdp.ConsumeBool() /* play_status */, + mFdp.ConsumeBool() /* queue */); + }, + [&]() { + device.SendFolderUpdate(mFdp.ConsumeBool() /* available_players */, + mFdp.ConsumeBool() /* addressed_player */, + mFdp.ConsumeBool() /* uids */); + }, + }); + invokeAVRCP(); + } + device.DeviceDisconnected(); +} - auto avrcp_request = TestPacketType<avrcp::Packet>::Make(Packet); - device.MessageReceived(1, avrcp_request); +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + AVRCPDeviceFuzzer avrcp_device_fuzzer(Data, Size); + avrcp_device_fuzzer.Process(); return 0; } } // namespace avrcp diff --git a/system/stack/btm/btm_sco_hfp_hal_linux.cc b/system/stack/btm/btm_sco_hfp_hal_linux.cc index fdb534628e..24dfbd2ed5 100644 --- a/system/stack/btm/btm_sco_hfp_hal_linux.cc +++ b/system/stack/btm/btm_sco_hfp_hal_linux.cc @@ -136,7 +136,7 @@ constexpr uint16_t HCI_DEV_NONE = 0xffff; int btsocket_open_mgmt(uint16_t hci) { int fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_NONBLOCK, BTPROTO_HCI); if (fd < 0) { - log::debug("Failed to open BT socket."); + log::debug("Failed to open BT socket, hci: %u", hci); return -errno; } @@ -364,7 +364,7 @@ bool enable_offload(bool enable) { static bool get_single_codec(int codec, bt_codec** out) { for (cached_codec_info& c : cached_codecs) { - if (c.inner.codec == codec) { + if (c.inner.codec == static_cast<uint64_t>(codec)) { *out = &c.inner; return true; } @@ -443,7 +443,7 @@ void set_codec_datapath(tBTA_AG_UUID_CODEC codec_uuid) { size_t get_packet_size(int codec) { for (const cached_codec_info& c : cached_codecs) { - if (c.inner.codec == codec) { + if (c.inner.codec == static_cast<uint64_t>(codec)) { return c.pkt_size; } } diff --git a/system/stack/smp/smp_act.cc b/system/stack/smp/smp_act.cc index f9c1580039..97fc68c165 100644 --- a/system/stack/smp/smp_act.cc +++ b/system/stack/smp/smp_act.cc @@ -535,12 +535,7 @@ void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) { p_cb->rcvd_cmd_len); p_cb->status = SMP_INVALID_PARAMETERS; } else { - if (com::android::bluetooth::flags:: - fix_pairing_failure_reason_from_remote()) { - p_cb->status = static_cast<tSMP_STATUS>(p_data->p_data[0]); - } else { - p_cb->status = p_data->status; - } + p_cb->status = static_cast<tSMP_STATUS>(p_data->p_data[0]); } /* Cancel pending auth complete timer if set */ |