summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TEST_MAPPING6
-rw-r--r--android/app/aidl/android/bluetooth/IBluetoothA2dp.aidl2
-rw-r--r--android/app/jni/com_android_bluetooth_gatt.cpp13
-rw-r--r--android/app/res/values/config.xml6
-rw-r--r--android/app/src/com/android/bluetooth/a2dp/A2dpService.java6
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java30
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/helpers/Image.java4
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java17
-rw-r--r--android/app/src/com/android/bluetooth/audio_util/helpers/Util.java17
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java5
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java42
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/helpers/AvrcpVersion.java10
-rw-r--r--android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java30
-rw-r--r--android/app/src/com/android/bluetooth/bass_client/BassClientService.java49
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java1
-rw-r--r--android/app/src/com/android/bluetooth/btservice/AdapterService.java69
-rw-r--r--android/app/src/com/android/bluetooth/btservice/PhonePolicy.java25
-rw-r--r--android/app/src/com/android/bluetooth/btservice/RemoteDevices.java324
-rw-r--r--android/app/src/com/android/bluetooth/gatt/AdvertiseBinder.kt63
-rw-r--r--android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java248
-rw-r--r--android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java51
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java11
-rw-r--r--android/app/src/com/android/bluetooth/hfp/HeadsetService.java9
-rw-r--r--android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java9
-rw-r--r--android/app/src/com/android/bluetooth/le_audio/LeAudioService.java78
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/ScanController.java19
-rw-r--r--android/app/src/com/android/bluetooth/le_scan/ScanManager.java93
-rw-r--r--android/app/src/com/android/bluetooth/tbs/TbsGeneric.java28
-rw-r--r--android/app/src/com/com/android/bluetooth/le_scan/BatchScanThrottler.java112
-rw-r--r--android/app/tests/unit/Android.bp1
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java6
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java18
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java14
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java14
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java58
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java6
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java9
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java41
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java65
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java22
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java24
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java165
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/BatchScanThrottlerTest.java202
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanControllerTest.java49
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java10
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGenericTest.java77
-rw-r--r--android/pandora/mmi2grpc/mmi2grpc/_rootcanal.py1
-rw-r--r--android/pandora/mmi2grpc/mmi2grpc/avrcp.py71
-rw-r--r--android/pandora/server/configs/pts_bot_tests_config.json35
-rw-r--r--android/pandora/server/src/A2dp.kt9
-rw-r--r--android/pandora/server/src/MediaPlayer.kt14
-rw-r--r--android/pandora/server/src/MediaPlayerBrowserService.kt20
-rw-r--r--flags/Android.bp1
-rw-r--r--flags/BUILD.gn1
-rw-r--r--flags/bta_dm.aconfig7
-rw-r--r--flags/gap.aconfig20
-rw-r--r--flags/hfp.aconfig10
-rw-r--r--flags/le_scanning.aconfig12
-rw-r--r--flags/leaudio.aconfig10
-rw-r--r--flags/security.aconfig10
-rw-r--r--framework/api/system-current.txt2
-rw-r--r--framework/java/android/bluetooth/BluetoothA2dp.java15
-rw-r--r--framework/java/android/bluetooth/BluetoothGatt.java195
-rw-r--r--framework/java/android/bluetooth/BluetoothSocket.java3
-rw-r--r--framework/tests/bumble/src/android/bluetooth/DckL2capTest.kt45
-rw-r--r--framework/tests/bumble/src/android/bluetooth/GattClientTest.java38
-rw-r--r--offload/hal/service.rs51
-rw-r--r--offload/hci/data.rs2
-rw-r--r--offload/leaudio/hci/proxy.rs10
-rw-r--r--offload/leaudio/hci/service.rs48
-rw-r--r--pandora/interfaces/pandora_experimental/mediaplayer.proto2
-rw-r--r--system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc3
-rw-r--r--system/audio_hal_interface/aidl/a2dp/a2dp_provider_info_unittest.cc2
-rw-r--r--system/audio_hal_interface/aidl/a2dp/codec_status_aidl.cc5
-rw-r--r--system/audio_hal_interface/fuzzer/README.md2
-rw-r--r--system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp2
-rw-r--r--system/audio_hal_interface/fuzzer/libbt_audio_hal_client_interface_fuzzer.cpp2
-rw-r--r--system/audio_hal_interface/hidl/client_interface_hidl_unittest.cc2
-rw-r--r--system/audio_hal_interface/hidl/codec_status_hidl.cc5
-rw-r--r--system/bta/av/bta_av_aact.cc74
-rw-r--r--system/bta/dm/bta_dm_disc.cc5
-rw-r--r--system/bta/hh/bta_hh_headtracker.cc5
-rw-r--r--system/bta/le_audio/client.cc38
-rw-r--r--system/bta/le_audio/le_audio_client_test.cc21
-rw-r--r--system/bta/le_audio/state_machine.cc3
-rw-r--r--system/bta/test/bta_disc_test.cc56
-rw-r--r--system/btif/include/btif_dm.h1
-rw-r--r--system/btif/include/btif_storage.h1
-rw-r--r--system/btif/src/btif_core.cc21
-rw-r--r--system/btif/src/btif_dm.cc158
-rw-r--r--system/btif/src/btif_storage.cc74
-rw-r--r--system/btif/src/btif_util.cc1
-rw-r--r--system/btif/test/btif_core_test.cc1
-rw-r--r--system/conf/interop_database.conf15
-rw-r--r--system/device/include/interop.h6
-rw-r--r--system/device/src/interop.cc2
-rw-r--r--system/gd/hci/distance_measurement_manager.cc61
-rw-r--r--system/gd/hci/le_advertising_manager.h4
-rw-r--r--system/gd/rust/linux/stack/src/bluetooth.rs19
-rw-r--r--system/gd/rust/linux/stack/src/lib.rs2
-rw-r--r--system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc4
-rw-r--r--system/gd/storage/config_keys.h1
-rw-r--r--system/include/hardware/ble_scanner.h2
-rw-r--r--system/include/hardware/bluetooth.h10
-rw-r--r--system/include/hardware/bt_av.h3
-rw-r--r--system/main/shim/ble_scanner_interface_impl.h2
-rw-r--r--system/main/shim/le_scanning_manager.cc19
-rw-r--r--system/pdl/hci/hci_packets.pdl2
-rw-r--r--system/profile/avrcp/Android.bp2
-rw-r--r--system/profile/avrcp/device.cc5
-rw-r--r--system/stack/Android.bp53
-rw-r--r--system/stack/a2dp/a2dp_codec_config.cc3
-rw-r--r--system/stack/a2dp/a2dp_vendor.cc24
-rw-r--r--system/stack/a2dp/a2dp_vendor_ldac.cc95
-rw-r--r--system/stack/a2dp/a2dp_vendor_ldac_decoder.cc281
-rw-r--r--system/stack/a2dp/a2dp_vendor_ldac_linux.cc28
-rw-r--r--system/stack/acl/ble_acl.cc2
-rw-r--r--system/stack/acl/btm_acl.cc13
-rw-r--r--system/stack/avrc/avrc_api.cc8
-rw-r--r--system/stack/btm/btm_ble.cc13
-rw-r--r--system/stack/btm/btm_ble_gap.cc29
-rw-r--r--system/stack/btm/btm_ble_int.h10
-rw-r--r--system/stack/btm/btm_ble_privacy.cc4
-rw-r--r--system/stack/btm/btm_ble_sec.cc9
-rw-r--r--system/stack/btm/btm_dev.cc7
-rw-r--r--system/stack/btm/btm_dev.h4
-rw-r--r--system/stack/btm/btm_devctl.cc35
-rw-r--r--system/stack/btm/btm_inq.cc34
-rw-r--r--system/stack/btm/btm_iot_config.cc5
-rw-r--r--system/stack/btm/btm_main.cc6
-rw-r--r--system/stack/btm/btm_sco.cc37
-rw-r--r--system/stack/btm/btm_sco.h1
-rw-r--r--system/stack/btm/btm_sec.cc20
-rw-r--r--system/stack/btm/btm_sec.h4
-rw-r--r--system/stack/btm/internal/btm_api.h1
-rw-r--r--system/stack/fuzzers/rfcomm_fuzzer.cc4
-rw-r--r--system/stack/gatt/gatt_attr.cc28
-rw-r--r--system/stack/include/a2dp_vendor_ldac.h30
-rw-r--r--system/stack/include/a2dp_vendor_ldac_decoder.h56
-rw-r--r--system/stack/include/avrc_api.h4
-rw-r--r--system/stack/include/ble_appearance.h446
-rw-r--r--system/stack/include/ble_hci_link_interface.h20
-rw-r--r--system/stack/include/bt_dev_class.h232
-rw-r--r--system/stack/include/btm_ble_api_types.h119
-rw-r--r--system/stack/include/btm_inq.h3
-rw-r--r--system/stack/include/btm_iot_config.h24
-rw-r--r--system/stack/include/sco_hci_link_interface.h3
-rw-r--r--system/stack/include/smp_status.h28
-rw-r--r--system/stack/l2cap/l2c_link.cc11
-rw-r--r--system/stack/rfcomm/port_rfc.cc6
-rw-r--r--system/stack/rfcomm/rfc_int.h1
-rw-r--r--system/stack/rfcomm/rfc_port_fsm.cc24
-rw-r--r--system/stack/rfcomm/rfc_port_if.cc7
-rw-r--r--system/stack/rfcomm/rfc_utils.cc28
-rw-r--r--system/stack/rnr/remote_name_request.cc4
-rw-r--r--system/stack/smp/smp_act.cc17
-rw-r--r--system/stack/smp/smp_api.cc4
-rw-r--r--system/stack/smp/smp_utils.cc2
-rw-r--r--system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc56
-rw-r--r--system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc12
-rw-r--r--system/stack/test/a2dp/misc_fake.cc21
-rw-r--r--system/stack/test/btm/stack_btm_dm_inq_db_test.cc3
-rw-r--r--system/stack/test/btm/stack_btm_sec_test.cc12
-rw-r--r--system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h1
-rw-r--r--system/stack/test/stack_a2dp_test.cc44
-rw-r--r--system/stack/test/stack_smp_test.cc6
-rw-r--r--system/test/headless/property.cc4
-rw-r--r--system/test/headless/property.h1
-rw-r--r--system/test/mock/mock_stack_btm_ble.cc11
-rw-r--r--system/test/mock/mock_stack_btm_ble.h26
-rw-r--r--system/test/mock/mock_stack_btm_ble_gap.cc19
-rw-r--r--system/test/mock/mock_stack_btm_devctl.cc10
-rw-r--r--system/test/mock/mock_stack_btm_inq.cc15
-rw-r--r--system/test/mock/mock_stack_btm_inq.h28
-rw-r--r--system/test/mock/mock_stack_btm_sco.cc7
-rw-r--r--system/test/mock/mock_stack_btm_sec.cc5
-rw-r--r--system/test/mock/mock_stack_btm_sec.h9
-rw-r--r--tools/rootcanal/model/controller/controller_properties.cc34
-rw-r--r--tools/rootcanal/model/controller/dual_mode_controller.cc9
-rw-r--r--tools/rootcanal/model/controller/dual_mode_controller.h1
-rw-r--r--tools/rootcanal/model/setup/test_command_handler.cc2
-rw-r--r--tools/rootcanal/packets/hci_packets.pdl1
-rw-r--r--tools/rootcanal/proto/rootcanal/configuration.proto2
-rwxr-xr-xtools/rootcanal/scripts/controller_info.py62
184 files changed, 3415 insertions, 2244 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 562f9717c8..d3205af4c9 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -136,9 +136,6 @@
"name": "net_test_performance"
},
{
- "name": "net_test_stack_a2dp_native"
- },
- {
"name": "net_test_stack_acl"
},
{
@@ -335,9 +332,6 @@
"name": "net_test_performance"
},
{
- "name": "net_test_stack_a2dp_native"
- },
- {
"name": "net_test_stack_acl"
},
{
diff --git a/android/app/aidl/android/bluetooth/IBluetoothA2dp.aidl b/android/app/aidl/android/bluetooth/IBluetoothA2dp.aidl
index bcfc95585d..fa5d1362ac 100644
--- a/android/app/aidl/android/bluetooth/IBluetoothA2dp.aidl
+++ b/android/app/aidl/android/bluetooth/IBluetoothA2dp.aidl
@@ -53,7 +53,7 @@ interface IBluetoothA2dp {
boolean isA2dpPlaying(in BluetoothDevice device, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)")
List<BluetoothCodecType> getSupportedCodecTypes();
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true)")
BluetoothCodecStatus getCodecStatus(in BluetoothDevice device, in AttributionSource attributionSource);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT,android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true)")
oneway void setCodecConfigPreference(in BluetoothDevice device, in BluetoothCodecConfig codecConfig, in AttributionSource attributionSource);
diff --git a/android/app/jni/com_android_bluetooth_gatt.cpp b/android/app/jni/com_android_bluetooth_gatt.cpp
index 014668bfd0..704f7d7341 100644
--- a/android/app/jni/com_android_bluetooth_gatt.cpp
+++ b/android/app/jni/com_android_bluetooth_gatt.cpp
@@ -1524,16 +1524,6 @@ static void gattClientReadRemoteRssiNative(JNIEnv* env, jobject /* object */, ji
sGattIf->client->read_remote_rssi(clientif, str2addr(env, address));
}
-void set_scan_params_cmpl_cb(int client_if, uint8_t status) {
- std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
- CallbackEnv sCallbackEnv(__func__);
- if (!sCallbackEnv.valid() || !mScanCallbacksObj) {
- return;
- }
- sCallbackEnv->CallVoidMethod(mScanCallbacksObj, method_onScanParamSetupCompleted, status,
- client_if);
-}
-
static void gattSetScanParametersNative(JNIEnv* /* env */, jobject /* object */, jint client_if,
jint scan_interval_unit, jint scan_window_unit,
jint scan_phy) {
@@ -1541,8 +1531,7 @@ static void gattSetScanParametersNative(JNIEnv* /* env */, jobject /* object */,
return;
}
sScanner->SetScanParameters(client_if, /* use active scan */ 0x01, scan_interval_unit,
- scan_window_unit, scan_phy,
- base::Bind(&set_scan_params_cmpl_cb, client_if));
+ scan_window_unit, scan_phy);
}
void scan_filter_param_cb(uint8_t client_if, uint8_t avbl_space, uint8_t action, uint8_t status) {
diff --git a/android/app/res/values/config.xml b/android/app/res/values/config.xml
index 7418000e8e..0bb72b5ca8 100644
--- a/android/app/res/values/config.xml
+++ b/android/app/res/values/config.xml
@@ -138,12 +138,6 @@
<integer name="a2dp_source_codec_priority_lc3">6001</integer>
<integer name="a2dp_source_codec_priority_opus">7001</integer>
- <!-- For enabling the AVRCP Target Cover Artowrk feature-->
- <bool name="avrcp_target_enable_cover_art">true</bool>
-
- <!-- Enable support for URI based images. Off by default due to increased memory usage -->
- <bool name="avrcp_target_cover_art_uri_images">false</bool>
-
<!-- Package that is responsible for user interaction on pairing request,
success or cancel.
Receives:
diff --git a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
index 136a0d4621..100076127b 100644
--- a/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
+++ b/android/app/src/com/android/bluetooth/a2dp/A2dpService.java
@@ -50,7 +50,6 @@ import android.media.BluetoothProfileConnectionInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -1515,12 +1514,14 @@ public class A2dpService extends ProfileService {
@Override
public BluetoothCodecStatus getCodecStatus(
BluetoothDevice device, AttributionSource source) {
+ requireNonNull(device);
A2dpService service = getServiceAndEnforceConnect(source);
if (service == null) {
return null;
}
- service.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null);
+ Utils.enforceCdmAssociationIfNotBluetoothPrivileged(
+ service, service.mCompanionDeviceManager, source, device);
return service.getCodecStatus(device);
}
@@ -1530,6 +1531,7 @@ public class A2dpService extends ProfileService {
BluetoothDevice device,
BluetoothCodecConfig codecConfig,
AttributionSource source) {
+ requireNonNull(device);
A2dpService service = getServiceAndEnforceConnect(source);
if (service == null) {
return;
diff --git a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
index b04f684f34..e062814766 100644
--- a/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
+++ b/android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java
@@ -784,6 +784,10 @@ public class MediaPlayerList {
}
}
+ public boolean isVfsCoverArtEnabled() {
+ return Util.areUriImagesSupported();
+ }
+
/**
* Adds a {@link MediaController} to the {@link #mMediaPlayers} map and returns its ID.
*
@@ -985,6 +989,19 @@ public class MediaPlayerList {
mActivePlayerId = playerId;
+ if (Utils.isPtsTestMode()) {
+ sendFolderUpdate(true, true, false);
+ } else if (Flags.setAddressedPlayer() && Flags.browsingRefactor()) {
+ // If the browsing refactor flag is not active, addressed player should always be 0.
+ // If the new active player has been set by Addressed player key event
+ // We don't send an addressed player update.
+ if (mActivePlayerId != mAddressedPlayerId) {
+ mAddressedPlayerId = mActivePlayerId;
+ Log.d(TAG, "setActivePlayer AddressedPlayer changed to " + mAddressedPlayerId);
+ sendFolderUpdate(false, true, false);
+ }
+ }
+
MediaPlayerWrapper player = getActivePlayer();
if (player == null) return;
@@ -1002,19 +1019,6 @@ public class MediaPlayerList {
return;
}
- if (Utils.isPtsTestMode()) {
- sendFolderUpdate(true, true, false);
- } else if (Flags.setAddressedPlayer() && Flags.browsingRefactor()) {
- // If the browsing refactor flag is not active, addressed player should always be 0.
- // If the new active player has been set by Addressed player key event
- // We don't send an addressed player update.
- if (mActivePlayerId != mAddressedPlayerId) {
- mAddressedPlayerId = mActivePlayerId;
- Log.d(TAG, "setActivePlayer AddressedPlayer changed to " + mAddressedPlayerId);
- sendFolderUpdate(false, true, false);
- }
- }
-
MediaData data = player.getCurrentMediaData();
if (mAudioPlaybackIsActive) {
data.state = mCurrMediaData.state;
diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java
index fc106e9a95..d89a6afddf 100644
--- a/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java
+++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Image.java
@@ -60,7 +60,7 @@ public class Image {
Bitmap bmp_album_art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
Bitmap bmp_icon = metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON);
- if (mContext != null && Util.areUriImagesSupported(mContext)) {
+ if (Util.areUriImagesSupported()) {
uri_art = metadata.getString(MediaMetadata.METADATA_KEY_ART_URI);
uri_album_art = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI);
uri_icon = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI);
@@ -92,7 +92,7 @@ public class Image {
Bitmap bmp_album_art = bundle.getParcelable(MediaMetadata.METADATA_KEY_ALBUM_ART);
Bitmap bmp_icon = bundle.getParcelable(MediaMetadata.METADATA_KEY_DISPLAY_ICON);
- if (mContext != null && Util.areUriImagesSupported(mContext)) {
+ if (Util.areUriImagesSupported()) {
uri_art = bundle.getString(MediaMetadata.METADATA_KEY_ART_URI);
uri_album_art = bundle.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI);
uri_icon = bundle.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI);
diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java
index 02ca4fbd5c..63791acb29 100644
--- a/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java
+++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Metadata.java
@@ -23,8 +23,6 @@ import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaSession;
import android.os.Bundle;
-import com.android.bluetooth.R;
-
import java.util.Objects;
public class Metadata implements Cloneable {
@@ -201,7 +199,7 @@ public class Metadata implements Cloneable {
mMetadata.duration = "" + data.getLong(MediaMetadata.METADATA_KEY_DURATION);
}
if ((mContext != null
- && Util.areUriImagesSupported(mContext)
+ && Util.areUriImagesSupported()
&& (data.containsKey(MediaMetadata.METADATA_KEY_ART_URI)
|| data.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)
|| data.containsKey(
@@ -233,7 +231,7 @@ public class Metadata implements Cloneable {
if (desc.getIconBitmap() != null) {
mMetadata.image = new Image(mContext, desc.getIconBitmap());
} else if (mContext != null
- && Util.areUriImagesSupported(mContext)
+ && Util.areUriImagesSupported()
&& desc.getIconUri() != null) {
mMetadata.image = new Image(mContext, desc.getIconUri());
}
@@ -281,7 +279,7 @@ public class Metadata implements Cloneable {
mMetadata.duration = "" + bundle.getLong(MediaMetadata.METADATA_KEY_DURATION);
}
if ((mContext != null
- && Util.areUriImagesSupported(mContext)
+ && Util.areUriImagesSupported()
&& (bundle.containsKey(MediaMetadata.METADATA_KEY_ART_URI)
|| bundle.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)
|| bundle.containsKey(
@@ -296,13 +294,8 @@ public class Metadata implements Cloneable {
/** Elect to use default values in the Metadata in place of any missing values */
public Builder useDefaults() {
- if (mMetadata.mediaId == null) {
- mMetadata.mediaId = EMPTY_MEDIA_ID;
- }
- if (mMetadata.title == null) {
- mMetadata.title =
- mContext != null ? mContext.getString(R.string.not_provided) : EMPTY_TITLE;
- }
+ if (mMetadata.mediaId == null) mMetadata.mediaId = EMPTY_MEDIA_ID;
+ if (mMetadata.title == null) mMetadata.title = EMPTY_TITLE;
if (mMetadata.artist == null) mMetadata.artist = EMPTY_ARTIST;
if (mMetadata.album == null) mMetadata.album = EMPTY_ALBUM;
if (mMetadata.trackNum == null) mMetadata.trackNum = EMPTY_TRACK_NUM;
diff --git a/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java b/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java
index 32597edc75..877a315c88 100644
--- a/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java
+++ b/android/app/src/com/android/bluetooth/audio_util/helpers/Util.java
@@ -21,9 +21,10 @@ import android.content.pm.PackageManager;
import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaSession;
+import android.os.SystemProperties;
import android.util.Log;
-import com.android.bluetooth.R;
+import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
@@ -31,6 +32,13 @@ import java.util.List;
class Util {
public static String TAG = "audio_util.Util";
+ private static final String VFS_COVER_ART_ENABLED_PROPERTY =
+ "bluetooth.profile.avrcp.target.vfs_coverart.enabled";
+
+ @VisibleForTesting
+ static Boolean sUriImagesSupport =
+ SystemProperties.getBoolean(VFS_COVER_ART_ENABLED_PROPERTY, false);
+
// TODO (apanicke): Remove this prefix later, for now it makes debugging easier.
public static final String NOW_PLAYING_PREFIX = "NowPlayingId";
@@ -49,13 +57,12 @@ class Util {
}
/**
- * Get whether or not Bluetooth is configured to support URI images or not.
+ * Get whether or not Bluetooth is configured to support URI images.
*
* <p>Note that creating URI images will dramatically increase memory usage.
*/
- public static boolean areUriImagesSupported(Context context) {
- if (context == null) return false;
- return context.getResources().getBoolean(R.bool.avrcp_target_cover_art_uri_images);
+ public static boolean areUriImagesSupported() {
+ return sUriImagesSupport.booleanValue();
}
/** Translate a MediaItem to audio_util's Metadata */
diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java
index 26d7d3e48d..46805f404c 100644
--- a/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java
+++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpCoverArtService.java
@@ -62,8 +62,9 @@ public class AvrcpCoverArtService {
// Native interface
private AvrcpNativeInterface mNativeInterface;
- public AvrcpCoverArtService() {
- mNativeInterface = AvrcpNativeInterface.getInstance();
+ // The native interface must be a parameter here in order to be able to mock AvrcpTargetService
+ public AvrcpCoverArtService(AvrcpNativeInterface nativeInterface) {
+ mNativeInterface = nativeInterface;
mAcceptThread = new SocketAcceptor();
mStorage = new AvrcpCoverArtStorage(COVER_ART_STORAGE_MAX_ITEMS);
}
diff --git a/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java b/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
index b6aa7cf8b6..068db0f024 100644
--- a/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
+++ b/android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java
@@ -36,8 +36,8 @@ import android.view.KeyEvent;
import com.android.bluetooth.BluetoothEventLogger;
import com.android.bluetooth.BluetoothMetricsProto;
-import com.android.bluetooth.R;
import com.android.bluetooth.a2dp.A2dpService;
+import com.android.bluetooth.audio_util.ListItem;
import com.android.bluetooth.audio_util.MediaData;
import com.android.bluetooth.audio_util.MediaPlayerList;
import com.android.bluetooth.audio_util.MediaPlayerWrapper;
@@ -98,6 +98,8 @@ public class AvrcpTargetService extends ProfileService {
private static AvrcpTargetService sInstance = null;
+ private final boolean mIsVfsCoverArtEnabled;
+
public AvrcpTargetService(AdapterService adapterService) {
this(
requireNonNull(adapterService),
@@ -142,13 +144,11 @@ public class AvrcpTargetService extends ProfileService {
mMediaPlayerList.init(new ListCallback());
}
- if (!getResources().getBoolean(R.bool.avrcp_target_enable_cover_art)) {
- mAvrcpCoverArtService = null;
- } else if (!mAvrcpVersion.isAtleastVersion(AvrcpVersion.AVRCP_VERSION_1_6)) {
+ if (!mAvrcpVersion.isAtleastVersion(AvrcpVersion.AVRCP_VERSION_1_6)) {
Log.e(TAG, "Please use AVRCP version 1.6 to enable cover art");
mAvrcpCoverArtService = null;
} else {
- AvrcpCoverArtService coverArtService = new AvrcpCoverArtService();
+ AvrcpCoverArtService coverArtService = new AvrcpCoverArtService(mNativeInterface);
if (coverArtService.start()) {
mAvrcpCoverArtService = coverArtService;
} else {
@@ -157,6 +157,8 @@ public class AvrcpTargetService extends ProfileService {
}
}
+ mIsVfsCoverArtEnabled = mMediaPlayerList.isVfsCoverArtEnabled();
+
mReceiver = new AvrcpBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -399,8 +401,7 @@ public class AvrcpTargetService extends ProfileService {
Metadata getCurrentSongInfo() {
Metadata metadata = mMediaPlayerList.getCurrentSongInfo();
if (mAvrcpCoverArtService != null && metadata.image != null) {
- String imageHandle = mAvrcpCoverArtService.storeImage(metadata.image);
- if (imageHandle != null) metadata.image.setImageHandle(imageHandle);
+ metadata.image.setImageHandle(mAvrcpCoverArtService.storeImage(metadata.image));
}
return metadata;
}
@@ -433,26 +434,20 @@ public class AvrcpTargetService extends ProfileService {
List<Metadata> getNowPlayingList() {
String currentMediaId = getCurrentMediaId();
Metadata currentTrack = null;
- String imageHandle = null;
List<Metadata> nowPlayingList = mMediaPlayerList.getNowPlayingList();
if (mAvrcpCoverArtService != null) {
for (Metadata metadata : nowPlayingList) {
if (TextUtils.equals(metadata.mediaId, currentMediaId)) {
currentTrack = metadata;
} else if (metadata.image != null) {
- imageHandle = mAvrcpCoverArtService.storeImage(metadata.image);
- if (imageHandle != null) {
- metadata.image.setImageHandle(imageHandle);
- }
+ metadata.image.setImageHandle(mAvrcpCoverArtService.storeImage(metadata.image));
}
}
// Always store the current item from the queue last so we know the image is in storage
if (currentTrack != null) {
- imageHandle = mAvrcpCoverArtService.storeImage(currentTrack.image);
- if (imageHandle != null) {
- currentTrack.image.setImageHandle(imageHandle);
- }
+ currentTrack.image.setImageHandle(
+ mAvrcpCoverArtService.storeImage(currentTrack.image));
}
}
return nowPlayingList;
@@ -491,7 +486,20 @@ public class AvrcpTargetService extends ProfileService {
/** See {@link MediaPlayerList#getFolderItems}. */
void getFolderItems(int playerId, String mediaId, MediaPlayerList.GetFolderItemsCallback cb) {
- mMediaPlayerList.getFolderItems(playerId, mediaId, cb);
+ mMediaPlayerList.getFolderItems(
+ playerId,
+ mediaId,
+ (id, results) -> {
+ if (mIsVfsCoverArtEnabled && mAvrcpCoverArtService != null) {
+ for (ListItem item : results) {
+ if (item != null && item.song != null && item.song.image != null) {
+ item.song.image.setImageHandle(
+ mAvrcpCoverArtService.storeImage(item.song.image));
+ }
+ }
+ }
+ cb.run(id, results);
+ });
}
/** See {@link MediaPlayerList#playItem}. */
diff --git a/android/app/src/com/android/bluetooth/avrcp/helpers/AvrcpVersion.java b/android/app/src/com/android/bluetooth/avrcp/helpers/AvrcpVersion.java
index a3ab9192e9..c475db1ef1 100644
--- a/android/app/src/com/android/bluetooth/avrcp/helpers/AvrcpVersion.java
+++ b/android/app/src/com/android/bluetooth/avrcp/helpers/AvrcpVersion.java
@@ -18,6 +18,8 @@ package com.android.bluetooth.avrcp;
import android.os.SystemProperties;
+import com.android.bluetooth.flags.Flags;
+
/** A class to represent an AVRCP version */
final class AvrcpVersion {
public static final AvrcpVersion AVRCP_VERSION_1_3 = new AvrcpVersion(1, 3);
@@ -36,8 +38,12 @@ final class AvrcpVersion {
public int minor;
public static AvrcpVersion getCurrentSystemPropertiesValue() {
- // Make sure this default version agrees with avrc_api.h's "AVRC_DEFAULT_VERSION"
- String version = SystemProperties.get(AVRCP_VERSION_PROPERTY, AVRCP_VERSION_1_5_STRING);
+ // Make sure this default version agrees with AVRC_GetProfileVersion
+
+ String defaultVersion =
+ Flags.avrcp16Default() ? AVRCP_VERSION_1_6_STRING : AVRCP_VERSION_1_5_STRING;
+ String version = SystemProperties.get(AVRCP_VERSION_PROPERTY, defaultVersion);
+
switch (version) {
case AVRCP_VERSION_1_3_STRING:
return AVRCP_VERSION_1_3;
diff --git a/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java b/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java
index 95388baf78..dd720077a0 100644
--- a/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java
+++ b/android/app/src/com/android/bluetooth/avrcp/helpers/CoverArt.java
@@ -40,7 +40,12 @@ import java.security.NoSuchAlgorithmException;
*/
public class CoverArt {
private static final String TAG = CoverArt.class.getSimpleName();
- private static final BipPixel PIXEL_THUMBNAIL = BipPixel.createFixed(200, 200);
+
+ // The size in pixels of the thumbnail sides.
+ private static final int THUMBNAIL_SIZE = 200;
+
+ private static final BipPixel PIXEL_THUMBNAIL =
+ BipPixel.createFixed(THUMBNAIL_SIZE, THUMBNAIL_SIZE);
private String mImageHandle = null;
private Bitmap mImage = null;
@@ -50,7 +55,7 @@ public class CoverArt {
// Create a scaled version of the image for now, as consumers don't need
// anything larger than this at the moment. Also makes each image gathered
// the same dimensions for hashing purposes.
- mImage = Bitmap.createScaledBitmap(image.getImage(), 200, 200, false);
+ mImage = Bitmap.createScaledBitmap(image.getImage(), THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
}
/**
@@ -133,13 +138,15 @@ public class CoverArt {
BipEncoding encoding = descriptor.getEncoding();
BipPixel pixel = descriptor.getPixel();
- if (encoding.getType() == BipEncoding.JPEG && PIXEL_THUMBNAIL.equals(pixel)) {
+ int encodingType = encoding.getType();
+ if ((encodingType == BipEncoding.JPEG || encodingType == BipEncoding.PNG)
+ && PIXEL_THUMBNAIL.equals(pixel)) {
return true;
}
return false;
}
- /** Get the cover artwork image bytes as a 200 x 200 JPEG thumbnail */
+ /** Get the cover artwork image bytes as a THUMBNAIL_SIZE x THUMBNAIL_SIZE JPEG thumbnail */
public byte[] getThumbnail() {
debug("GetImageThumbnail()");
if (mImage == null) return null;
@@ -160,12 +167,19 @@ public class CoverArt {
return null;
}
BipImageProperties.Builder builder = new BipImageProperties.Builder();
- BipEncoding encoding = new BipEncoding(BipEncoding.JPEG);
- BipPixel pixel = BipPixel.createFixed(200, 200);
- BipImageFormat format = BipImageFormat.createNative(encoding, pixel, -1);
+
+ BipEncoding jpgEncoding = new BipEncoding(BipEncoding.JPEG);
+ BipEncoding pngEncoding = new BipEncoding(BipEncoding.PNG);
+ BipPixel jpgPixel = BipPixel.createFixed(THUMBNAIL_SIZE, THUMBNAIL_SIZE);
+ BipPixel pngPixel = BipPixel.createFixed(THUMBNAIL_SIZE, THUMBNAIL_SIZE);
+
+ BipImageFormat jpgNativeFormat = BipImageFormat.createNative(jpgEncoding, jpgPixel, -1);
+ BipImageFormat pngVariantFormat =
+ BipImageFormat.createVariant(pngEncoding, pngPixel, THUMBNAIL_SIZE, null);
builder.setImageHandle(mImageHandle);
- builder.addNativeFormat(format);
+ builder.addNativeFormat(jpgNativeFormat);
+ builder.addVariantFormat(pngVariantFormat);
BipImageProperties properties = builder.build();
return properties;
diff --git a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
index 53657b16a6..0daef0175a 100644
--- a/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
+++ b/android/app/src/com/android/bluetooth/bass_client/BassClientService.java
@@ -2499,6 +2499,28 @@ public class BassClientService extends ProfileService {
BluetoothDevice srcDevice = getDeviceForSyncHandle(syncHandle);
mSyncHandleToDeviceMap.remove(syncHandle);
int broadcastId = getBroadcastIdForSyncHandle(syncHandle);
+ if (leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()) {
+ synchronized (mPendingSourcesToAdd) {
+ Iterator<AddSourceData> iterator = mPendingSourcesToAdd.iterator();
+ while (iterator.hasNext()) {
+ AddSourceData pendingSourcesToAdd = iterator.next();
+ if (pendingSourcesToAdd.mSourceMetadata.getBroadcastId() == broadcastId) {
+ iterator.remove();
+ }
+ }
+ }
+ synchronized (mSinksWaitingForPast) {
+ Iterator<Map.Entry<BluetoothDevice, Pair<Integer, Integer>>> iterator =
+ mSinksWaitingForPast.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry<BluetoothDevice, Pair<Integer, Integer>> entry = iterator.next();
+ int broadcastIdForPast = entry.getValue().first;
+ if (broadcastId == broadcastIdForPast) {
+ iterator.remove();
+ }
+ }
+ }
+ }
mSyncHandleToBroadcastIdMap.remove(syncHandle);
if (srcDevice != null) {
mPeriodicAdvertisementResultMap.get(srcDevice).remove(broadcastId);
@@ -4054,7 +4076,10 @@ public class BassClientService extends ProfileService {
mUnicastSourceStreamStatus = Optional.of(status);
if (status == STATUS_LOCAL_STREAM_REQUESTED) {
- if (areReceiversReceivingOnlyExternalBroadcast(getConnectedDevices())) {
+ if ((leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()
+ && hasPrimaryDeviceManagedExternalBroadcast())
+ || (!leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()
+ && areReceiversReceivingOnlyExternalBroadcast(getConnectedDevices()))) {
if (leaudioBroadcastAssistantPeripheralEntrustment()) {
cacheSuspendingSources(BassConstants.INVALID_BROADCAST_ID);
List<Pair<BluetoothLeBroadcastReceiveState, BluetoothDevice>> sourcesToStop =
@@ -4067,11 +4092,13 @@ public class BassClientService extends ProfileService {
suspendAllReceiversSourceSynchronization();
}
}
- for (Map.Entry<Integer, PauseType> entry : mPausedBroadcastIds.entrySet()) {
- Integer broadcastId = entry.getKey();
- PauseType pauseType = entry.getValue();
- if (pauseType != PauseType.HOST_INTENTIONAL) {
- suspendReceiversSourceSynchronization(broadcastId);
+ if (!leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator()) {
+ for (Map.Entry<Integer, PauseType> entry : mPausedBroadcastIds.entrySet()) {
+ Integer broadcastId = entry.getKey();
+ PauseType pauseType = entry.getValue();
+ if (pauseType != PauseType.HOST_INTENTIONAL) {
+ suspendReceiversSourceSynchronization(broadcastId);
+ }
}
}
} else if (status == STATUS_LOCAL_STREAM_SUSPENDED) {
@@ -4235,6 +4262,16 @@ public class BassClientService extends ProfileService {
return activeSinks;
}
+ /** Get sink devices synced to the broadcasts by broadcast id */
+ public List<BluetoothDevice> getSyncedBroadcastSinks(int broadcastId) {
+ return getConnectedDevices().stream()
+ .filter(
+ device ->
+ getAllSources(device).stream()
+ .anyMatch(rs -> rs.getBroadcastId() == broadcastId))
+ .toList();
+ }
+
private boolean isSyncedToBroadcastStream(Long syncState) {
return syncState != BassConstants.BCAST_RCVR_STATE_BIS_SYNC_NOT_SYNC_TO_BIS
&& syncState != BassConstants.BCAST_RCVR_STATE_BIS_SYNC_FAILED_SYNC_TO_BIG;
diff --git a/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java b/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java
index 981b2db0c7..9ebe10d181 100644
--- a/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java
+++ b/android/app/src/com/android/bluetooth/btservice/AbstractionLayer.java
@@ -50,6 +50,7 @@ public final class AbstractionLayer {
static final int BT_PROPERTY_REMOTE_ASHA_TRUNCATED_HISYNCID = 0X16;
static final int BT_PROPERTY_REMOTE_MODEL_NUM = 0x17;
static final int BT_PROPERTY_LPP_OFFLOAD_FEATURES = 0x1B;
+ static final int BT_PROPERTY_UUIDS_LE = 0x1C;
public static final int BT_DEVICE_TYPE_BREDR = 0x01;
public static final int BT_DEVICE_TYPE_BLE = 0x02;
diff --git a/android/app/src/com/android/bluetooth/btservice/AdapterService.java b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
index c7ce8669bc..cba0af9ae6 100644
--- a/android/app/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/android/app/src/com/android/bluetooth/btservice/AdapterService.java
@@ -28,6 +28,7 @@ import static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERA
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;
import static android.bluetooth.BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
import static android.bluetooth.BluetoothDevice.TRANSPORT_AUTO;
+import static android.bluetooth.BluetoothProfile.getProfileName;
import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
@@ -183,6 +184,7 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1553,46 +1555,45 @@ public class AdapterService extends Service {
@VisibleForTesting
void setProfileServiceState(int profileId, int state) {
+ Instant start = Instant.now();
+ String logHdr = "setProfileServiceState(" + getProfileName(profileId) + ", " + state + "):";
+
if (state == BluetoothAdapter.STATE_ON) {
- if (!mStartedProfiles.containsKey(profileId)) {
- ProfileService profileService = PROFILE_CONSTRUCTORS.get(profileId).apply(this);
- mStartedProfiles.put(profileId, profileService);
- addProfile(profileService);
- profileService.start();
- profileService.setAvailable(true);
- // With `Flags.scanManagerRefactor()` GattService initialization is pushed back to
- // `ON` state instead of `BLE_ON`. Here we ensure mGattService is set prior
- // to other Profiles using it.
- if (profileId == BluetoothProfile.GATT && Flags.scanManagerRefactor()) {
- mGattService = GattService.getGattService();
- }
- onProfileServiceStateChanged(profileService, BluetoothAdapter.STATE_ON);
- } else {
- Log.e(
- TAG,
- "setProfileServiceState("
- + BluetoothProfile.getProfileName(profileId)
- + ", STATE_ON): profile is already started");
+ if (mStartedProfiles.containsKey(profileId)) {
+ Log.wtf(TAG, logHdr + " profile is already started");
+ return;
}
+ Log.d(TAG, logHdr + " starting profile");
+ ProfileService profileService = PROFILE_CONSTRUCTORS.get(profileId).apply(this);
+ mStartedProfiles.put(profileId, profileService);
+ addProfile(profileService);
+ profileService.start();
+ profileService.setAvailable(true);
+ // With `Flags.scanManagerRefactor()` GattService initialization is pushed back to
+ // `ON` state instead of `BLE_ON`. Here we ensure mGattService is set prior
+ // to other Profiles using it.
+ if (profileId == BluetoothProfile.GATT && Flags.scanManagerRefactor()) {
+ mGattService = GattService.getGattService();
+ }
+ onProfileServiceStateChanged(profileService, BluetoothAdapter.STATE_ON);
} else if (state == BluetoothAdapter.STATE_OFF) {
ProfileService profileService = mStartedProfiles.remove(profileId);
- if (profileService != null) {
- profileService.setAvailable(false);
- onProfileServiceStateChanged(profileService, BluetoothAdapter.STATE_OFF);
- profileService.stop();
- removeProfile(profileService);
- profileService.cleanup();
- if (profileService.getBinder() != null) {
- profileService.getBinder().cleanup();
- }
- } else {
- Log.e(
- TAG,
- "setProfileServiceState("
- + BluetoothProfile.getProfileName(profileId)
- + ", STATE_OFF): profile is already stopped");
+ if (profileService == null) {
+ Log.wtf(TAG, logHdr + " profile is already stopped");
+ return;
+ }
+ Log.d(TAG, logHdr + " stopping profile");
+ profileService.setAvailable(false);
+ onProfileServiceStateChanged(profileService, BluetoothAdapter.STATE_OFF);
+ profileService.stop();
+ removeProfile(profileService);
+ profileService.cleanup();
+ if (profileService.getBinder() != null) {
+ profileService.getBinder().cleanup();
}
}
+ Instant end = Instant.now();
+ Log.d(TAG, logHdr + " completed in " + Duration.between(start, end).toMillis() + "ms");
}
private void setAllProfileServiceStates(int[] profileIds, int state) {
diff --git a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
index 475da0dba1..47a5d9991f 100644
--- a/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
+++ b/android/app/src/com/android/bluetooth/btservice/PhonePolicy.java
@@ -274,6 +274,27 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
&& hap.getConnectionPolicy(device) != CONNECTION_POLICY_FORBIDDEN;
}
+ private boolean shouldBlockBroadcastForHapDevice(BluetoothDevice device, ParcelUuid[] uuids) {
+ if (!Flags.leaudioDisableBroadcastForHapDevice()) {
+ Log.i(TAG, "disableBroadcastForHapDevice: Flag is disabled");
+ return false;
+ }
+
+ HapClientService hap = mFactory.getHapClientService();
+ if (hap == null) {
+ Log.e(TAG, "shouldBlockBroadcastForHapDevice: No HapClientService");
+ return false;
+ }
+
+ if (!SystemProperties.getBoolean(SYSPROP_HAP_ENABLED, true)) {
+ Log.i(TAG, "shouldBlockBroadcastForHapDevice: SystemProperty is overridden to false");
+ return false;
+ }
+
+ return Utils.arrayContains(uuids, BluetoothUuid.HAS)
+ && hap.getConnectionPolicy(device) == CONNECTION_POLICY_ALLOWED;
+ }
+
// Policy implementation, all functions MUST be private
private void processInitProfilePriorities(BluetoothDevice device, ParcelUuid[] uuids) {
String log = "processInitProfilePriorities(" + device + "): ";
@@ -518,7 +539,7 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
if ((bcService != null)
&& Utils.arrayContains(uuids, BluetoothUuid.BASS)
&& (bcService.getConnectionPolicy(device) == CONNECTION_POLICY_UNKNOWN)) {
- if (isLeAudioProfileAllowed) {
+ if (isLeAudioProfileAllowed && !shouldBlockBroadcastForHapDevice(device, uuids)) {
Log.d(TAG, log + "Setting BASS priority");
if (mAutoConnectProfilesSupported) {
bcService.setConnectionPolicy(device, CONNECTION_POLICY_ALLOWED);
@@ -531,7 +552,7 @@ public class PhonePolicy implements AdapterService.BluetoothStateCallback {
CONNECTION_POLICY_ALLOWED);
}
} else {
- Log.d(TAG, log + "LE_AUDIO is not allowed: Clear BASS priority");
+ Log.d(TAG, log + "LE_AUDIO Broadcast is not allowed: Clear BASS priority");
mAdapterService
.getDatabase()
.setProfileConnectionPolicy(
diff --git a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
index f0bad17e64..f297d905ac 100644
--- a/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
+++ b/android/app/src/com/android/bluetooth/btservice/RemoteDevices.java
@@ -345,7 +345,8 @@ public class RemoteDevices {
private String mModelName;
@VisibleForTesting int mBondState;
@VisibleForTesting int mDeviceType;
- @VisibleForTesting ParcelUuid[] mUuids;
+ @VisibleForTesting ParcelUuid[] mUuidsBrEdr;
+ @VisibleForTesting ParcelUuid[] mUuidsLe;
private BluetoothSinkAudioPolicy mAudioPolicy;
DeviceProperties() {
@@ -506,20 +507,71 @@ public class RemoteDevices {
}
/**
- * @return the mUuids
+ * @return the UUIDs on LE and Classic transport
*/
ParcelUuid[] getUuids() {
synchronized (mObject) {
- return mUuids;
+ /* When we bond dual mode device, and discover LE and Classic services, stack would
+ * return LE and Classic UUIDs separately, but Java apps expect them merged.
+ */
+ int combinedUuidsLength =
+ (mUuidsBrEdr != null ? mUuidsBrEdr.length : 0)
+ + (mUuidsLe != null ? mUuidsLe.length : 0);
+ if (!Flags.separateServiceStorage() || combinedUuidsLength == 0) {
+ return mUuidsBrEdr;
+ }
+
+ java.util.LinkedHashSet<ParcelUuid> result =
+ new java.util.LinkedHashSet<ParcelUuid>();
+ if (mUuidsBrEdr != null) {
+ for (ParcelUuid uuid : mUuidsBrEdr) {
+ result.add(uuid);
+ }
+ }
+
+ if (mUuidsLe != null) {
+ for (ParcelUuid uuid : mUuidsLe) {
+ result.add(uuid);
+ }
+ }
+
+ return result.toArray(new ParcelUuid[combinedUuidsLength]);
+ }
+ }
+
+ /**
+ * @return just classic transport UUIDS
+ */
+ ParcelUuid[] getUuidsBrEdr() {
+ synchronized (mObject) {
+ return mUuidsBrEdr;
+ }
+ }
+
+ /**
+ * @param uuids the mUuidsBrEdr to set
+ */
+ void setUuidsBrEdr(ParcelUuid[] uuids) {
+ synchronized (mObject) {
+ this.mUuidsBrEdr = uuids;
+ }
+ }
+
+ /**
+ * @return the mUuidsLe
+ */
+ ParcelUuid[] getUuidsLe() {
+ synchronized (mObject) {
+ return mUuidsLe;
}
}
/**
- * @param uuids the mUuids to set
+ * @param uuids the mUuidsLe to set
*/
- void setUuids(ParcelUuid[] uuids) {
+ void setUuidsLe(ParcelUuid[] uuids) {
synchronized (mObject) {
- this.mUuids = uuids;
+ this.mUuidsLe = uuids;
}
}
@@ -636,7 +688,8 @@ public class RemoteDevices {
cachedBluetoothDevice issued a connect using the local cached copy of uuids,
without waiting for the ACTION_UUID intent.
This was resulting in multiple calls to connect().*/
- mUuids = null;
+ mUuidsBrEdr = null;
+ mUuidsLe = null;
mAlias = null;
}
}
@@ -988,147 +1041,168 @@ public class RemoteDevices {
return;
}
+ boolean uuids_updated = false;
+
for (int j = 0; j < types.length; j++) {
type = types[j];
val = values[j];
- if (val.length > 0) {
- synchronized (mObject) {
- debugLog("Update property, device=" + bdDevice + ", type: " + type);
- switch (type) {
- case AbstractionLayer.BT_PROPERTY_BDNAME:
- final String newName = new String(val);
- if (newName.equals(deviceProperties.getName())) {
- debugLog("Skip name update for " + bdDevice);
- break;
- }
- deviceProperties.setName(newName);
- List<String> wordBreakdownList =
- MetricsLogger.getInstance().getWordBreakdownList(newName);
- if (SdkLevel.isAtLeastU()) {
- MetricsLogger.getInstance()
- .uploadRestrictedBluetothDeviceName(wordBreakdownList);
- }
- intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
- intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProperties.getName());
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mAdapterService.sendBroadcast(
- intent,
- BLUETOOTH_CONNECT,
- Utils.getTempBroadcastOptions().toBundle());
- debugLog("Remote device name is: " + deviceProperties.getName());
- break;
- case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME:
- deviceProperties.setAlias(bdDevice, new String(val));
- debugLog("Remote device alias is: " + deviceProperties.getAlias());
- break;
- case AbstractionLayer.BT_PROPERTY_BDADDR:
- deviceProperties.setAddress(val);
- debugLog(
- "Remote Address is:"
- + Utils.getRedactedAddressStringFromByte(val));
+ if (val.length == 0) {
+ continue;
+ }
+
+ synchronized (mObject) {
+ debugLog("Update property, device=" + bdDevice + ", type: " + type);
+ switch (type) {
+ case AbstractionLayer.BT_PROPERTY_BDNAME:
+ final String newName = new String(val);
+ if (newName.equals(deviceProperties.getName())) {
+ debugLog("Skip name update for " + bdDevice);
break;
- case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
- final int newBluetoothClass = Utils.byteArrayToInt(val);
- if (newBluetoothClass == deviceProperties.getBluetoothClass()) {
- debugLog(
- "Skip class update, device="
- + bdDevice
- + ", cod=0x"
- + Integer.toHexString(newBluetoothClass));
- break;
- }
- deviceProperties.setBluetoothClass(newBluetoothClass);
- intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
- intent.putExtra(
- BluetoothDevice.EXTRA_CLASS,
- new BluetoothClass(deviceProperties.getBluetoothClass()));
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mAdapterService.sendBroadcast(
- intent,
- BLUETOOTH_CONNECT,
- Utils.getTempBroadcastOptions().toBundle());
+ }
+ deviceProperties.setName(newName);
+ List<String> wordBreakdownList =
+ MetricsLogger.getInstance().getWordBreakdownList(newName);
+ if (SdkLevel.isAtLeastU()) {
+ MetricsLogger.getInstance()
+ .uploadRestrictedBluetothDeviceName(wordBreakdownList);
+ }
+ intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
+ intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProperties.getName());
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mAdapterService.sendBroadcast(
+ intent,
+ BLUETOOTH_CONNECT,
+ Utils.getTempBroadcastOptions().toBundle());
+ debugLog("Remote device name is: " + deviceProperties.getName());
+ break;
+ case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME:
+ deviceProperties.setAlias(bdDevice, new String(val));
+ debugLog("Remote device alias is: " + deviceProperties.getAlias());
+ break;
+ case AbstractionLayer.BT_PROPERTY_BDADDR:
+ deviceProperties.setAddress(val);
+ debugLog(
+ "Remote Address is:" + Utils.getRedactedAddressStringFromByte(val));
+ break;
+ case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
+ final int newBluetoothClass = Utils.byteArrayToInt(val);
+ if (newBluetoothClass == deviceProperties.getBluetoothClass()) {
debugLog(
- "Remote class update, device="
+ "Skip class update, device="
+ bdDevice
+ ", cod=0x"
+ Integer.toHexString(newBluetoothClass));
break;
- case AbstractionLayer.BT_PROPERTY_UUIDS:
+ }
+ deviceProperties.setBluetoothClass(newBluetoothClass);
+ intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
+ intent.putExtra(
+ BluetoothDevice.EXTRA_CLASS,
+ new BluetoothClass(deviceProperties.getBluetoothClass()));
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mAdapterService.sendBroadcast(
+ intent,
+ BLUETOOTH_CONNECT,
+ Utils.getTempBroadcastOptions().toBundle());
+ debugLog(
+ "Remote class update, device="
+ + bdDevice
+ + ", cod=0x"
+ + Integer.toHexString(newBluetoothClass));
+ break;
+ case AbstractionLayer.BT_PROPERTY_UUIDS:
+ case AbstractionLayer.BT_PROPERTY_UUIDS_LE:
+ if (type == AbstractionLayer.BT_PROPERTY_UUIDS) {
final ParcelUuid[] newUuids = Utils.byteArrayToUuid(val);
- if (areUuidsEqual(newUuids, deviceProperties.getUuids())) {
+ if (areUuidsEqual(newUuids, deviceProperties.getUuidsBrEdr())) {
// SDP Skip adding UUIDs to property cache if equal
debugLog("Skip uuids update for " + bdDevice.getAddress());
MetricsLogger.getInstance()
.cacheCount(BluetoothProtoEnums.SDP_UUIDS_EQUAL_SKIP, 1);
break;
}
- deviceProperties.setUuids(newUuids);
- if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) {
- // SDP Adding UUIDs to property cache and sending intent
- MetricsLogger.getInstance()
- .cacheCount(
- BluetoothProtoEnums.SDP_ADD_UUID_WITH_INTENT, 1);
- mAdapterService.deviceUuidUpdated(bdDevice);
- sendUuidIntent(bdDevice, deviceProperties, true);
- } else if (mAdapterService.getState()
- == BluetoothAdapter.STATE_BLE_ON) {
- // SDP Adding UUIDs to property cache but with no intent
- MetricsLogger.getInstance()
- .cacheCount(
- BluetoothProtoEnums.SDP_ADD_UUID_WITH_NO_INTENT, 1);
- mAdapterService.deviceUuidUpdated(bdDevice);
- } else {
- // SDP Silently dropping UUIDs and with no intent
+ deviceProperties.setUuidsBrEdr(newUuids);
+ } else if (type == AbstractionLayer.BT_PROPERTY_UUIDS_LE) {
+ final ParcelUuid[] newUuidsLe = Utils.byteArrayToUuid(val);
+ if (areUuidsEqual(newUuidsLe, deviceProperties.getUuidsLe())) {
+ // SDP Skip adding UUIDs to property cache if equal
+ debugLog("Skip LE uuids update for " + bdDevice.getAddress());
MetricsLogger.getInstance()
- .cacheCount(BluetoothProtoEnums.SDP_DROP_UUID, 1);
- }
- break;
- case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
- if (deviceProperties.isConsolidated()) {
+ .cacheCount(BluetoothProtoEnums.SDP_UUIDS_EQUAL_SKIP, 1);
break;
}
- // The device type from hal layer, defined in bluetooth.h,
- // matches the type defined in BluetoothDevice.java
- deviceProperties.setDeviceType(Utils.byteArrayToInt(val));
- break;
- case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI:
- // RSSI from hal is in one byte
- deviceProperties.setRssi(val[0]);
- break;
- case AbstractionLayer.BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER:
- deviceProperties.setIsCoordinatedSetMember(val[0] != 0);
- break;
- case AbstractionLayer.BT_PROPERTY_REMOTE_ASHA_CAPABILITY:
- deviceProperties.setAshaCapability(val[0]);
- break;
- case AbstractionLayer.BT_PROPERTY_REMOTE_ASHA_TRUNCATED_HISYNCID:
- deviceProperties.setAshaTruncatedHiSyncId(val[0]);
- break;
- case AbstractionLayer.BT_PROPERTY_REMOTE_MODEL_NUM:
- final String modelName = new String(val);
- debugLog("Remote device model name: " + modelName);
- deviceProperties.setModelName(modelName);
- BluetoothStatsLog.write(
- BluetoothStatsLog.BLUETOOTH_DEVICE_INFO_REPORTED,
- mAdapterService.obfuscateAddress(bdDevice),
- BluetoothProtoEnums.DEVICE_INFO_INTERNAL,
- LOG_SOURCE_DIS,
- null,
- modelName,
- null,
- null,
- mAdapterService.getMetricId(bdDevice),
- bdDevice.getAddressType(),
- 0,
- 0,
- 0);
+ deviceProperties.setUuidsLe(newUuidsLe);
+ }
+ uuids_updated = true;
+ break;
+ case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
+ if (deviceProperties.isConsolidated()) {
break;
- }
+ }
+ // The device type from hal layer, defined in bluetooth.h,
+ // matches the type defined in BluetoothDevice.java
+ deviceProperties.setDeviceType(Utils.byteArrayToInt(val));
+ break;
+ case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI:
+ // RSSI from hal is in one byte
+ deviceProperties.setRssi(val[0]);
+ break;
+ case AbstractionLayer.BT_PROPERTY_REMOTE_IS_COORDINATED_SET_MEMBER:
+ deviceProperties.setIsCoordinatedSetMember(val[0] != 0);
+ break;
+ case AbstractionLayer.BT_PROPERTY_REMOTE_ASHA_CAPABILITY:
+ deviceProperties.setAshaCapability(val[0]);
+ break;
+ case AbstractionLayer.BT_PROPERTY_REMOTE_ASHA_TRUNCATED_HISYNCID:
+ deviceProperties.setAshaTruncatedHiSyncId(val[0]);
+ break;
+ case AbstractionLayer.BT_PROPERTY_REMOTE_MODEL_NUM:
+ final String modelName = new String(val);
+ debugLog("Remote device model name: " + modelName);
+ deviceProperties.setModelName(modelName);
+ BluetoothStatsLog.write(
+ BluetoothStatsLog.BLUETOOTH_DEVICE_INFO_REPORTED,
+ mAdapterService.obfuscateAddress(bdDevice),
+ BluetoothProtoEnums.DEVICE_INFO_INTERNAL,
+ LOG_SOURCE_DIS,
+ null,
+ modelName,
+ null,
+ null,
+ mAdapterService.getMetricId(bdDevice),
+ bdDevice.getAddressType(),
+ 0,
+ 0,
+ 0);
+ break;
}
}
}
+
+ if (!uuids_updated) {
+ return;
+ }
+
+ /* uuids_updated == true
+ * We might have received LE and BREDR UUIDS separately, ensure that UUID intent is sent
+ * just once */
+
+ if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) {
+ // SDP Adding UUIDs to property cache and sending intent
+ MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_ADD_UUID_WITH_INTENT, 1);
+ mAdapterService.deviceUuidUpdated(bdDevice);
+ sendUuidIntent(bdDevice, deviceProperties, true);
+ } else if (mAdapterService.getState() == BluetoothAdapter.STATE_BLE_ON) {
+ // SDP Adding UUIDs to property cache but with no intent
+ MetricsLogger.getInstance()
+ .cacheCount(BluetoothProtoEnums.SDP_ADD_UUID_WITH_NO_INTENT, 1);
+ mAdapterService.deviceUuidUpdated(bdDevice);
+ } else {
+ // SDP Silently dropping UUIDs and with no intent
+ MetricsLogger.getInstance().cacheCount(BluetoothProtoEnums.SDP_DROP_UUID, 1);
+ }
}
void deviceFoundCallback(byte[] address) {
diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseBinder.kt b/android/app/src/com/android/bluetooth/gatt/AdvertiseBinder.kt
index 92aaf31101..66415cd82f 100644
--- a/android/app/src/com/android/bluetooth/gatt/AdvertiseBinder.kt
+++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseBinder.kt
@@ -66,28 +66,31 @@ class AdvertiseBinder(
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null)
}
- getManager(source)
- ?.startAdvertisingSet(
- parameters,
- advertiseData,
- scanResponse,
- periodicParameters,
- periodicData,
- duration,
- maxExtAdvEvents,
- serverIf,
- callback,
- source,
- )
+ getManager(source)?.let {
+ it.doOnAdvertiseThread {
+ it.startAdvertisingSet(
+ parameters,
+ advertiseData,
+ scanResponse,
+ periodicParameters,
+ periodicData,
+ duration,
+ maxExtAdvEvents,
+ serverIf,
+ callback,
+ source,
+ )
+ }
+ }
}
override fun stopAdvertisingSet(callback: IAdvertisingSetCallback, source: AttributionSource) {
- getManager(source)?.stopAdvertisingSet(callback)
+ getManager(source)?.let { it.doOnAdvertiseThread { it.stopAdvertisingSet(callback) } }
}
override fun getOwnAddress(advertiserId: Int, source: AttributionSource) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null)
- getManager(source)?.getOwnAddress(advertiserId)
+ getManager(source)?.let { it.doOnAdvertiseThread { it.getOwnAddress(advertiserId) } }
}
override fun enableAdvertisingSet(
@@ -97,7 +100,11 @@ class AdvertiseBinder(
maxExtAdvEvents: Int,
source: AttributionSource,
) {
- getManager(source)?.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread {
+ it.enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents)
+ }
+ }
}
override fun setAdvertisingData(
@@ -105,7 +112,9 @@ class AdvertiseBinder(
data: AdvertiseData?,
source: AttributionSource,
) {
- getManager(source)?.setAdvertisingData(advertiserId, data)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread { it.setAdvertisingData(advertiserId, data) }
+ }
}
override fun setScanResponseData(
@@ -113,7 +122,9 @@ class AdvertiseBinder(
data: AdvertiseData?,
source: AttributionSource,
) {
- getManager(source)?.setScanResponseData(advertiserId, data)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread { it.setScanResponseData(advertiserId, data) }
+ }
}
override fun setAdvertisingParameters(
@@ -127,7 +138,9 @@ class AdvertiseBinder(
) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED, null)
}
- getManager(source)?.setAdvertisingParameters(advertiserId, parameters)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread { it.setAdvertisingParameters(advertiserId, parameters) }
+ }
}
override fun setPeriodicAdvertisingParameters(
@@ -135,7 +148,9 @@ class AdvertiseBinder(
parameters: PeriodicAdvertisingParameters?,
source: AttributionSource,
) {
- getManager(source)?.setPeriodicAdvertisingParameters(advertiserId, parameters)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread { it.setPeriodicAdvertisingParameters(advertiserId, parameters) }
+ }
}
override fun setPeriodicAdvertisingData(
@@ -143,7 +158,9 @@ class AdvertiseBinder(
data: AdvertiseData?,
source: AttributionSource,
) {
- getManager(source)?.setPeriodicAdvertisingData(advertiserId, data)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread { it.setPeriodicAdvertisingData(advertiserId, data) }
+ }
}
override fun setPeriodicAdvertisingEnable(
@@ -151,6 +168,8 @@ class AdvertiseBinder(
enable: Boolean,
source: AttributionSource,
) {
- getManager(source)?.setPeriodicAdvertisingEnable(advertiserId, enable)
+ getManager(source)?.let {
+ it.doOnAdvertiseThread { it.setPeriodicAdvertisingEnable(advertiserId, enable) }
+ }
}
}
diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java
index 7e89f99055..6ed719cedc 100644
--- a/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java
+++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseManager.java
@@ -24,45 +24,52 @@ import android.bluetooth.le.PeriodicAdvertisingParameters;
import android.content.AttributionSource;
import android.os.Binder;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.IInterface;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
-import com.android.internal.annotations.GuardedBy;
+import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.VisibleForTesting;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
-/**
- * Manages Bluetooth LE advertising operations and interacts with bluedroid stack. TODO: add tests.
- */
-@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+/** Manages Bluetooth LE advertising operations. */
public class AdvertiseManager {
private static final String TAG = GattServiceConfig.TAG_PREFIX + "AdvertiseManager";
- private final GattService mService;
+ private static final long RUN_SYNC_WAIT_TIME_MS = 2000L;
+
+ private final AdapterService mService;
private final AdvertiseManagerNativeInterface mNativeInterface;
private final AdvertiseBinder mAdvertiseBinder;
private final AdvertiserMap mAdvertiserMap;
- @GuardedBy("itself")
private final Map<IBinder, AdvertiserInfo> mAdvertisers = new HashMap<>();
- private Handler mHandler;
- static int sTempRegistrationId = -1;
+ private final Handler mHandler;
+ private volatile boolean mIsAvailable = true;
+ @VisibleForTesting int mTempRegistrationId = -1;
- AdvertiseManager(GattService service) {
- this(service, AdvertiseManagerNativeInterface.getInstance(), new AdvertiserMap());
+ AdvertiseManager(AdapterService service, Looper advertiseLooper) {
+ this(
+ service,
+ advertiseLooper,
+ AdvertiseManagerNativeInterface.getInstance(),
+ new AdvertiserMap());
}
@VisibleForTesting
AdvertiseManager(
- GattService service,
+ AdapterService service,
+ Looper advertiseLooper,
AdvertiseManagerNativeInterface nativeInterface,
AdvertiserMap advertiserMap) {
Log.d(TAG, "advertise manager created");
@@ -70,42 +77,26 @@ public class AdvertiseManager {
mNativeInterface = nativeInterface;
mAdvertiserMap = advertiserMap;
- // Start a HandlerThread that handles advertising operations
mNativeInterface.init(this);
- HandlerThread thread = new HandlerThread("BluetoothAdvertiseManager");
- thread.start();
- mHandler = new Handler(thread.getLooper());
+ mHandler = new Handler(advertiseLooper);
mAdvertiseBinder = new AdvertiseBinder(service, this);
}
- // TODO(b/327849650): We shouldn't need this, it should be safe to do in the cleanup method. But
- // it would be a logic change.
- void clear() {
- mAdvertiserMap.clear();
- }
-
void cleanup() {
Log.d(TAG, "cleanup()");
- mAdvertiseBinder.cleanup();
- mNativeInterface.cleanup();
- synchronized (mAdvertisers) {
- mAdvertisers.clear();
- }
- sTempRegistrationId = -1;
-
- if (mHandler != null) {
- // Shut down the thread
- mHandler.removeCallbacksAndMessages(null);
- Looper looper = mHandler.getLooper();
- if (looper != null) {
- looper.quit();
- }
- mHandler = null;
- }
+ mIsAvailable = false;
+ mHandler.removeCallbacksAndMessages(null);
+ forceRunSyncOnAdvertiseThread(
+ () -> {
+ mAdvertiserMap.clear();
+ mAdvertiseBinder.cleanup();
+ mNativeInterface.cleanup();
+ mAdvertisers.clear();
+ });
}
void dump(StringBuilder sb) {
- mAdvertiserMap.dump(sb);
+ forceRunSyncOnAdvertiseThread(() -> mAdvertiserMap.dump(sb));
}
AdvertiseBinder getBinder() {
@@ -129,8 +120,12 @@ public class AdvertiseManager {
}
}
+ private interface CallbackWrapper {
+ void call() throws RemoteException;
+ }
+
IBinder toBinder(IAdvertisingSetCallback e) {
- return ((IInterface) e).asBinder();
+ return e.asBinder();
}
class AdvertisingSetDeathRecipient implements IBinder.DeathRecipient {
@@ -145,25 +140,22 @@ public class AdvertiseManager {
@Override
public void binderDied() {
Log.d(TAG, "Binder is dead - unregistering advertising set (" + mPackageName + ")!");
- stopAdvertisingSet(callback);
+ doOnAdvertiseThread(() -> stopAdvertisingSet(callback));
}
}
- Map.Entry<IBinder, AdvertiserInfo> findAdvertiser(int advertiserId) {
+ private Map.Entry<IBinder, AdvertiserInfo> findAdvertiser(int advertiserId) {
Map.Entry<IBinder, AdvertiserInfo> entry = null;
- synchronized (mAdvertisers) {
- for (Map.Entry<IBinder, AdvertiserInfo> e : mAdvertisers.entrySet()) {
- if (e.getValue().id == advertiserId) {
- entry = e;
- break;
- }
+ for (Map.Entry<IBinder, AdvertiserInfo> e : mAdvertisers.entrySet()) {
+ if (e.getValue().id == advertiserId) {
+ entry = e;
+ break;
}
}
return entry;
}
- void onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status)
- throws Exception {
+ void onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status) {
Log.d(
TAG,
"onAdvertisingSetStarted() - regId="
@@ -172,6 +164,7 @@ public class AdvertiseManager {
+ advertiserId
+ ", status="
+ status);
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(regId);
@@ -191,26 +184,24 @@ public class AdvertiseManager {
} else {
IBinder binder = entry.getKey();
binder.unlinkToDeath(entry.getValue().deathRecipient, 0);
- synchronized (mAdvertisers) {
- mAdvertisers.remove(binder);
- }
+ mAdvertisers.remove(binder);
AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(regId);
if (stats != null) {
- int instanceCount;
- synchronized (mAdvertisers) {
- instanceCount = mAdvertisers.size();
- }
- stats.recordAdvertiseStop(instanceCount);
+ stats.recordAdvertiseStop(mAdvertisers.size());
stats.recordAdvertiseErrorCount(status);
}
mAdvertiserMap.removeAppAdvertiseStats(regId);
}
- callback.onAdvertisingSetStarted(mAdvertiseBinder, advertiserId, txPower, status);
+ sendToCallback(
+ advertiserId,
+ () ->
+ callback.onAdvertisingSetStarted(
+ mAdvertiseBinder, advertiserId, txPower, status));
}
- void onAdvertisingEnabled(int advertiserId, boolean enable, int status) throws Exception {
+ void onAdvertisingEnabled(int advertiserId, boolean enable, int status) {
Log.d(
TAG,
"onAdvertisingSetEnabled() - advertiserId="
@@ -219,6 +210,7 @@ public class AdvertiseManager {
+ enable
+ ", status="
+ status);
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
@@ -230,16 +222,13 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onAdvertisingEnabled(advertiserId, enable, status);
+ sendToCallback(
+ advertiserId, () -> callback.onAdvertisingEnabled(advertiserId, enable, status));
if (!enable && status != 0) {
AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(advertiserId);
if (stats != null) {
- int instanceCount;
- synchronized (mAdvertisers) {
- instanceCount = mAdvertisers.size();
- }
- stats.recordAdvertiseStop(instanceCount);
+ stats.recordAdvertiseStop(mAdvertisers.size());
}
}
}
@@ -255,6 +244,7 @@ public class AdvertiseManager {
int serverIf,
IAdvertisingSetCallback callback,
AttributionSource attrSource) {
+ checkThread();
// If we are using an isolated server, force usage of an NRPA
if (serverIf != 0
&& parameters.getOwnAddressType()
@@ -289,7 +279,7 @@ public class AdvertiseManager {
throw new IllegalArgumentException("Can't link to advertiser's death");
}
- String deviceName = AdapterService.getAdapterService().getName();
+ String deviceName = mService.getName();
try {
byte[] advDataBytes = AdvertiseHelper.advertiseDataToBytes(advertiseData, deviceName);
byte[] scanResponseBytes =
@@ -297,10 +287,8 @@ public class AdvertiseManager {
byte[] periodicDataBytes =
AdvertiseHelper.advertiseDataToBytes(periodicData, deviceName);
- int cbId = --sTempRegistrationId;
- synchronized (mAdvertisers) {
- mAdvertisers.put(binder, new AdvertiserInfo(cbId, deathRecipient, callback));
- }
+ int cbId = --mTempRegistrationId;
+ mAdvertisers.put(binder, new AdvertiserInfo(cbId, deathRecipient, callback));
Log.d(TAG, "startAdvertisingSet() - reg_id=" + cbId + ", callback: " + binder);
@@ -340,9 +328,9 @@ public class AdvertiseManager {
}
}
- void onOwnAddressRead(int advertiserId, int addressType, String address)
- throws RemoteException {
+ void onOwnAddressRead(int advertiserId, int addressType, String address) {
Log.d(TAG, "onOwnAddressRead() advertiserId=" + advertiserId);
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
@@ -351,10 +339,12 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onOwnAddressRead(advertiserId, addressType, address);
+ sendToCallback(
+ advertiserId, () -> callback.onOwnAddressRead(advertiserId, addressType, address));
}
void getOwnAddress(int advertiserId) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "getOwnAddress() - bad advertiserId " + advertiserId);
@@ -364,13 +354,11 @@ public class AdvertiseManager {
}
void stopAdvertisingSet(IAdvertisingSetCallback callback) {
+ checkThread();
IBinder binder = toBinder(callback);
Log.d(TAG, "stopAdvertisingSet() " + binder);
- AdvertiserInfo adv;
- synchronized (mAdvertisers) {
- adv = mAdvertisers.remove(binder);
- }
+ AdvertiserInfo adv = mAdvertisers.remove(binder);
if (adv == null) {
Log.e(TAG, "stopAdvertisingSet() - no client found for callback");
return;
@@ -397,6 +385,7 @@ public class AdvertiseManager {
}
void enableAdvertisingSet(int advertiserId, boolean enable, int duration, int maxExtAdvEvents) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "enableAdvertisingSet() - bad advertiserId " + advertiserId);
@@ -408,12 +397,13 @@ public class AdvertiseManager {
}
void setAdvertisingData(int advertiserId, AdvertiseData data) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "setAdvertisingData() - bad advertiserId " + advertiserId);
return;
}
- String deviceName = AdapterService.getAdapterService().getName();
+ String deviceName = mService.getName();
try {
mNativeInterface.setAdvertisingData(
advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName));
@@ -430,12 +420,13 @@ public class AdvertiseManager {
}
void setScanResponseData(int advertiserId, AdvertiseData data) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "setScanResponseData() - bad advertiserId " + advertiserId);
return;
}
- String deviceName = AdapterService.getAdapterService().getName();
+ String deviceName = mService.getName();
try {
mNativeInterface.setScanResponseData(
advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName));
@@ -452,6 +443,7 @@ public class AdvertiseManager {
}
void setAdvertisingParameters(int advertiserId, AdvertisingSetParameters parameters) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "setAdvertisingParameters() - bad advertiserId " + advertiserId);
@@ -464,6 +456,7 @@ public class AdvertiseManager {
void setPeriodicAdvertisingParameters(
int advertiserId, PeriodicAdvertisingParameters parameters) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "setPeriodicAdvertisingParameters() - bad advertiserId " + advertiserId);
@@ -475,12 +468,13 @@ public class AdvertiseManager {
}
void setPeriodicAdvertisingData(int advertiserId, AdvertiseData data) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "setPeriodicAdvertisingData() - bad advertiserId " + advertiserId);
return;
}
- String deviceName = AdapterService.getAdapterService().getName();
+ String deviceName = mService.getName();
try {
mNativeInterface.setPeriodicAdvertisingData(
advertiserId, AdvertiseHelper.advertiseDataToBytes(data, deviceName));
@@ -497,6 +491,7 @@ public class AdvertiseManager {
}
void setPeriodicAdvertisingEnable(int advertiserId, boolean enable) {
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
Log.w(TAG, "setPeriodicAdvertisingEnable() - bad advertiserId " + advertiserId);
@@ -505,7 +500,8 @@ public class AdvertiseManager {
mNativeInterface.setPeriodicAdvertisingEnable(advertiserId, enable);
}
- void onAdvertisingDataSet(int advertiserId, int status) throws Exception {
+ void onAdvertisingDataSet(int advertiserId, int status) {
+ checkThread();
Log.d(TAG, "onAdvertisingDataSet() advertiserId=" + advertiserId + ", status=" + status);
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
@@ -515,10 +511,11 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onAdvertisingDataSet(advertiserId, status);
+ sendToCallback(advertiserId, () -> callback.onAdvertisingDataSet(advertiserId, status));
}
- void onScanResponseDataSet(int advertiserId, int status) throws Exception {
+ void onScanResponseDataSet(int advertiserId, int status) {
+ checkThread();
Log.d(TAG, "onScanResponseDataSet() advertiserId=" + advertiserId + ", status=" + status);
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
@@ -528,11 +525,10 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onScanResponseDataSet(advertiserId, status);
+ sendToCallback(advertiserId, () -> callback.onScanResponseDataSet(advertiserId, status));
}
- void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status)
- throws Exception {
+ void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) {
Log.d(
TAG,
"onAdvertisingParametersUpdated() advertiserId="
@@ -541,6 +537,7 @@ public class AdvertiseManager {
+ txPower
+ ", status="
+ status);
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
@@ -549,16 +546,19 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onAdvertisingParametersUpdated(advertiserId, txPower, status);
+ sendToCallback(
+ advertiserId,
+ () -> callback.onAdvertisingParametersUpdated(advertiserId, txPower, status));
}
- void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) throws Exception {
+ void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) {
Log.d(
TAG,
"onPeriodicAdvertisingParametersUpdated() advertiserId="
+ advertiserId
+ ", status="
+ status);
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
@@ -569,16 +569,19 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onPeriodicAdvertisingParametersUpdated(advertiserId, status);
+ sendToCallback(
+ advertiserId,
+ () -> callback.onPeriodicAdvertisingParametersUpdated(advertiserId, status));
}
- void onPeriodicAdvertisingDataSet(int advertiserId, int status) throws Exception {
+ void onPeriodicAdvertisingDataSet(int advertiserId, int status) {
Log.d(
TAG,
"onPeriodicAdvertisingDataSet() advertiserId="
+ advertiserId
+ ", status="
+ status);
+ checkThread();
Map.Entry<IBinder, AdvertiserInfo> entry = findAdvertiser(advertiserId);
if (entry == null) {
@@ -587,11 +590,11 @@ public class AdvertiseManager {
}
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onPeriodicAdvertisingDataSet(advertiserId, status);
+ sendToCallback(
+ advertiserId, () -> callback.onPeriodicAdvertisingDataSet(advertiserId, status));
}
- void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status)
- throws Exception {
+ void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) {
Log.d(
TAG,
"onPeriodicAdvertisingEnabled() advertiserId="
@@ -604,9 +607,12 @@ public class AdvertiseManager {
Log.i(TAG, "onAdvertisingSetEnable() - bad advertiserId " + advertiserId);
return;
}
+ checkThread();
IAdvertisingSetCallback callback = entry.getValue().callback;
- callback.onPeriodicAdvertisingEnabled(advertiserId, enable, status);
+ sendToCallback(
+ advertiserId,
+ () -> callback.onPeriodicAdvertisingEnabled(advertiserId, enable, status));
AppAdvertiseStats stats = mAdvertiserMap.getAppAdvertiseStatsById(advertiserId);
if (stats != null) {
@@ -614,4 +620,52 @@ public class AdvertiseManager {
}
}
+ void doOnAdvertiseThread(Runnable r) {
+ if (mIsAvailable) {
+ if (Flags.advertiseThread()) {
+ mHandler.post(
+ () -> {
+ if (mIsAvailable) {
+ r.run();
+ }
+ });
+ } else {
+ r.run();
+ }
+ }
+ }
+
+ private void forceRunSyncOnAdvertiseThread(Runnable r) {
+ if (!Flags.advertiseThread()) {
+ r.run();
+ return;
+ }
+ final CompletableFuture<Void> future = new CompletableFuture<>();
+ mHandler.postAtFrontOfQueue(
+ () -> {
+ r.run();
+ future.complete(null);
+ });
+ try {
+ future.get(RUN_SYNC_WAIT_TIME_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ Log.w(TAG, "Unable to complete sync task: " + e);
+ }
+ }
+
+ private void checkThread() {
+ if (Flags.advertiseThread()
+ && !mHandler.getLooper().isCurrentThread()
+ && !Utils.isInstrumentationTestMode()) {
+ throw new IllegalStateException("Not on advertise thread");
+ }
+ }
+
+ private void sendToCallback(int advertiserId, CallbackWrapper wrapper) {
+ try {
+ wrapper.call();
+ } catch (RemoteException e) {
+ Log.i(TAG, "RemoteException in callback for advertiserId: " + advertiserId);
+ }
+ }
}
diff --git a/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java b/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java
index 215c709970..6cdd47f97e 100644
--- a/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java
+++ b/android/app/src/com/android/bluetooth/gatt/AdvertiseManagerNativeInterface.java
@@ -19,11 +19,12 @@ package com.android.bluetooth.gatt;
import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.PeriodicAdvertisingParameters;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
/** Native interface for AdvertiseManager */
-@VisibleForTesting
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public class AdvertiseManagerNativeInterface {
private static final String TAG = AdvertiseManagerNativeInterface.class.getSimpleName();
@@ -121,43 +122,47 @@ public class AdvertiseManagerNativeInterface {
setPeriodicAdvertisingEnableNative(advertiserId, enable);
}
- void onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status)
- throws Exception {
- mManager.onAdvertisingSetStarted(regId, advertiserId, txPower, status);
+ void onAdvertisingSetStarted(int regId, int advertiserId, int txPower, int status) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onAdvertisingSetStarted(regId, advertiserId, txPower, status));
}
- void onOwnAddressRead(int advertiserId, int addressType, String address) throws Exception {
- mManager.onOwnAddressRead(advertiserId, addressType, address);
+ void onOwnAddressRead(int advertiserId, int addressType, String address) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onOwnAddressRead(advertiserId, addressType, address));
}
- void onAdvertisingEnabled(int advertiserId, boolean enable, int status) throws Exception {
- mManager.onAdvertisingEnabled(advertiserId, enable, status);
+ void onAdvertisingEnabled(int advertiserId, boolean enable, int status) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onAdvertisingEnabled(advertiserId, enable, status));
}
- void onAdvertisingDataSet(int advertiserId, int status) throws Exception {
- mManager.onAdvertisingDataSet(advertiserId, status);
+ void onAdvertisingDataSet(int advertiserId, int status) {
+ mManager.doOnAdvertiseThread(() -> mManager.onAdvertisingDataSet(advertiserId, status));
}
- void onScanResponseDataSet(int advertiserId, int status) throws Exception {
- mManager.onScanResponseDataSet(advertiserId, status);
+ void onScanResponseDataSet(int advertiserId, int status) {
+ mManager.doOnAdvertiseThread(() -> mManager.onScanResponseDataSet(advertiserId, status));
}
- void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status)
- throws Exception {
- mManager.onAdvertisingParametersUpdated(advertiserId, txPower, status);
+ void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onAdvertisingParametersUpdated(advertiserId, txPower, status));
}
- void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) throws Exception {
- mManager.onPeriodicAdvertisingParametersUpdated(advertiserId, status);
+ void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onPeriodicAdvertisingParametersUpdated(advertiserId, status));
}
- void onPeriodicAdvertisingDataSet(int advertiserId, int status) throws Exception {
- mManager.onPeriodicAdvertisingDataSet(advertiserId, status);
+ void onPeriodicAdvertisingDataSet(int advertiserId, int status) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onPeriodicAdvertisingDataSet(advertiserId, status));
}
- void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status)
- throws Exception {
- mManager.onPeriodicAdvertisingEnabled(advertiserId, enable, status);
+ void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) {
+ mManager.doOnAdvertiseThread(
+ () -> mManager.onPeriodicAdvertisingEnabled(advertiserId, enable, status));
}
private native void initializeNative();
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index cc2e759f61..e9563f8908 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -51,6 +51,7 @@ import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Build;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -156,6 +157,7 @@ public class GattService extends ProfileService {
private final DistanceMeasurementManager mDistanceMeasurementManager;
private final ActivityManager mActivityManager;
private final PackageManager mPackageManager;
+ private final HandlerThread mHandlerThread;
public GattService(AdapterService adapterService) {
super(requireNonNull(adapterService));
@@ -169,7 +171,12 @@ public class GattService extends ProfileService {
mNativeInterface = GattObjectsFactory.getInstance().getNativeInterface();
mNativeInterface.init(this);
- mAdvertiseManager = new AdvertiseManager(this);
+
+ // Create a thread to handle LE operations
+ mHandlerThread = new HandlerThread("Bluetooth LE");
+ mHandlerThread.start();
+
+ mAdvertiseManager = new AdvertiseManager(mAdapterService, mHandlerThread.getLooper());
if (!Flags.scanManagerRefactor()) {
mScanController = new ScanController(adapterService);
@@ -209,7 +216,6 @@ public class GattService extends ProfileService {
if (mScanController != null) {
mScanController.stop();
}
- mAdvertiseManager.clear();
mClientMap.clear();
mRestrictedHandles.clear();
mServerMap.clear();
@@ -224,6 +230,7 @@ public class GattService extends ProfileService {
mNativeInterface.cleanup();
mAdvertiseManager.cleanup();
mDistanceMeasurementManager.cleanup();
+ mHandlerThread.quit();
}
/** This is only used when Flags.scanManagerRefactor() is true. */
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
index 949db48483..179b7fafb0 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -1502,9 +1502,6 @@ public class HeadsetService extends ProfileService {
} else {
broadcastActiveDevice(mActiveDevice);
}
- if (Flags.updateActiveDeviceInBandRingtone()) {
- updateInbandRinging(device, true);
- }
} else if (shouldPersistAudio()) {
if (Utils.isScoManagedByAudioEnabled()) {
// tell Audio Framework that active device changed
@@ -1546,9 +1543,9 @@ public class HeadsetService extends ProfileService {
} else {
broadcastActiveDevice(mActiveDevice);
}
- if (Flags.updateActiveDeviceInBandRingtone()) {
- updateInbandRinging(device, true);
- }
+ }
+ if (Flags.updateActiveDeviceInBandRingtone()) {
+ updateInbandRinging(device, true);
}
}
return true;
diff --git a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
index fd56faa613..fb0ed9d2f0 100644
--- a/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
+++ b/android/app/src/com/android/bluetooth/hfp/HeadsetStateMachine.java
@@ -55,7 +55,6 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
-import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -1122,12 +1121,6 @@ class HeadsetStateMachine extends StateMachine {
}
}
break;
- case INTENT_SCO_VOLUME_CHANGED:
- if (Flags.hfpAllowVolumeChangeWithoutSco()) {
- // when flag is removed, remove INTENT_SCO_VOLUME_CHANGED case in AudioOn
- processIntentScoVolume((Intent) message.obj, mDevice);
- }
- break;
case INTENT_CONNECTION_ACCESS_REPLY:
handleAccessPermissionResult((Intent) message.obj);
break;
@@ -1630,8 +1623,6 @@ class HeadsetStateMachine extends StateMachine {
break;
}
case INTENT_SCO_VOLUME_CHANGED:
- // TODO: b/362313390 Remove this case once the fix is in place because this
- // message will be handled by the ConnectedBase state.
processIntentScoVolume((Intent) message.obj, mDevice);
break;
case STACK_EVENT:
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index 230526ca1a..9f281bd1e8 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -81,6 +81,7 @@ import android.util.Pair;
import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.Utils;
+import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.bass_client.BassClientService;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
@@ -90,6 +91,7 @@ import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.csip.CsipSetCoordinatorService;
import com.android.bluetooth.flags.Flags;
import com.android.bluetooth.hap.HapClientService;
+import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.tbs.TbsGatt;
@@ -102,6 +104,7 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -1655,6 +1658,31 @@ public class LeAudioService extends ProfileService {
&& groupId == mUnicastGroupIdDeactivatedForBroadcastTransition;
}
+ /** Get local broadcast receiving devices */
+ public Set<BluetoothDevice> getLocalBroadcastReceivers() {
+ if (mBroadcastDescriptors == null) {
+ Log.e(TAG, "getLocalBroadcastReceivers: Invalid Broadcast Descriptors");
+ return Collections.emptySet();
+ }
+
+ BassClientService bassClientService = getBassClientService();
+ if (bassClientService == null) {
+ Log.e(TAG, "getLocalBroadcastReceivers: Bass service not available");
+ return Collections.emptySet();
+ }
+
+ Set<BluetoothDevice> deviceList = new HashSet<>();
+ for (Map.Entry<Integer, LeAudioBroadcastDescriptor> entry :
+ mBroadcastDescriptors.entrySet()) {
+ if (!entry.getValue().mState.equals(LeAudioStackEvent.BROADCAST_STATE_STOPPED)) {
+ List<BluetoothDevice> devices =
+ bassClientService.getSyncedBroadcastSinks(entry.getKey());
+ deviceList.addAll(devices);
+ }
+ }
+ return deviceList;
+ }
+
private boolean areBroadcastsAllStopped() {
if (mBroadcastDescriptors == null) {
Log.e(TAG, "areBroadcastsAllStopped: Invalid Broadcast Descriptors");
@@ -2805,17 +2833,52 @@ public class LeAudioService extends ProfileService {
}
}
- private void handleGroupHealthAction(int groupId, int action) {
- Log.d(
+ private void disableLeAudioAndFallbackToLegacyAudioProfiles(int groupId) {
+ Log.i(
TAG,
- "handleGroupHealthAction: groupId: "
+ "Disabling LE Audio for group: "
+ groupId
- + " action: "
- + action
- + ", not implemented");
+ + " and falling back to legacy profiles");
+ A2dpService a2dpService = mServiceFactory.getA2dpService();
+ HeadsetService hsService = mServiceFactory.getHeadsetService();
+ HearingAidService hearingAidService = mServiceFactory.getHearingAidService();
+ boolean isDualMode = Utils.isDualModeAudioEnabled();
+
+ List<BluetoothDevice> leAudioActiveGroupDevices = getGroupDevices(groupId);
+
+ for (BluetoothDevice activeGroupDevice : leAudioActiveGroupDevices) {
+ Log.d(TAG, "Disable LE_AUDIO for the device: " + activeGroupDevice);
+ final ParcelUuid[] uuids = mAdapterService.getRemoteUuids(activeGroupDevice);
+
+ setConnectionPolicy(activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ if (hsService != null && !isDualMode && Utils.arrayContains(uuids, BluetoothUuid.HFP)) {
+ Log.d(TAG, "Enable HFP for the device: " + activeGroupDevice);
+ hsService.setConnectionPolicy(
+ activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ }
+ if (a2dpService != null
+ && !isDualMode
+ && (Utils.arrayContains(uuids, BluetoothUuid.A2DP_SINK)
+ || Utils.arrayContains(uuids, BluetoothUuid.ADV_AUDIO_DIST))) {
+ Log.d(TAG, "Enable A2DP for the device: " + activeGroupDevice);
+ a2dpService.setConnectionPolicy(
+ activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ }
+ if (hearingAidService != null
+ && Utils.arrayContains(uuids, BluetoothUuid.HEARING_AID)) {
+ Log.d(TAG, "Enable ASHA for the device: " + activeGroupDevice);
+ hearingAidService.setConnectionPolicy(
+ activeGroupDevice, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
+ }
+ }
+ }
+
+ private void handleGroupHealthAction(int groupId, int action) {
+ Log.d(TAG, "handleGroupHealthAction: groupId: " + groupId + " action: " + action);
BluetoothDevice device = getLeadDeviceForTheGroup(groupId);
switch (action) {
- case LeAudioStackEvent.HEALTH_RECOMMENDATION_ACTION_DISABLE:
+ case com.android.bluetooth.le_audio.LeAudioStackEvent
+ .HEALTH_RECOMMENDATION_ACTION_DISABLE:
MetricsLogger.getInstance()
.count(
mAdapterService.isLeAudioAllowed(device)
@@ -2824,6 +2887,7 @@ public class LeAudioService extends ProfileService {
: BluetoothProtoEnums
.LE_AUDIO_NONALLOWLIST_GROUP_HEALTH_STATUS_BAD,
1);
+ disableLeAudioAndFallbackToLegacyAudioProfiles(groupId);
break;
case LeAudioStackEvent.HEALTH_RECOMMENDATION_ACTION_CONSIDER_DISABLING:
MetricsLogger.getInstance()
diff --git a/android/app/src/com/android/bluetooth/le_scan/ScanController.java b/android/app/src/com/android/bluetooth/le_scan/ScanController.java
index a8f5a4025e..7f39fdaaf1 100644
--- a/android/app/src/com/android/bluetooth/le_scan/ScanController.java
+++ b/android/app/src/com/android/bluetooth/le_scan/ScanController.java
@@ -91,7 +91,7 @@ public class ScanController {
private static final int TRUNCATED_RESULT_SIZE = 11;
/** The default floor value for LE batch scan report delays greater than 0 */
- @VisibleForTesting static final long DEFAULT_REPORT_DELAY_FLOOR = 5000;
+ static final long DEFAULT_REPORT_DELAY_FLOOR = 5000L;
private static final int NUM_SCAN_EVENTS_KEPT = 20;
@@ -759,17 +759,19 @@ public class ScanController {
}
}
}
- if (permittedResults.isEmpty()) {
- return;
- }
}
if (client.hasDisavowedLocation) {
permittedResults.removeIf(mLocationDenylistPredicate);
}
+ if (permittedResults.isEmpty()) {
+ mScanManager.callbackDone(scannerId, status);
+ return;
+ }
if (app.mCallback != null) {
app.mCallback.onBatchScanResults(permittedResults);
+ mScanManager.batchScanResultDelivered();
} else {
// PendingIntent based
try {
@@ -791,6 +793,9 @@ public class ScanController {
@SuppressWarnings("NonApiType")
private void sendBatchScanResults(
ScannerMap.ScannerApp app, ScanClient client, ArrayList<ScanResult> results) {
+ if (results.isEmpty()) {
+ return;
+ }
try {
if (app.mCallback != null) {
if (mScanManager.isAutoBatchScanClientEnabled(client)) {
@@ -811,6 +816,7 @@ public class ScanController {
Log.e(TAG, "Exception: " + e);
handleDeadScanClient(client);
}
+ mScanManager.batchScanResultDelivered();
}
// Check and deliver scan results for different scan clients.
@@ -833,14 +839,11 @@ public class ScanController {
}
}
}
- if (permittedResults.isEmpty()) {
- return;
- }
}
if (client.filters == null || client.filters.isEmpty()) {
sendBatchScanResults(app, client, permittedResults);
- // TODO: Question to reviewer: Shouldn't there be a return here?
+ return;
}
// Reconstruct the scan results.
ArrayList<ScanResult> results = new ArrayList<ScanResult>();
diff --git a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java
index 78f759fb13..e946b3afcf 100644
--- a/android/app/src/com/android/bluetooth/le_scan/ScanManager.java
+++ b/android/app/src/com/android/bluetooth/le_scan/ScanManager.java
@@ -146,6 +146,7 @@ public class ScanManager {
@VisibleForTesting boolean mIsConnecting;
@VisibleForTesting int mProfilesConnecting;
private int mProfilesConnected, mProfilesDisconnecting;
+ private final BatchScanThrottler mBatchScanThrottler;
@VisibleForTesting
static class UidImportance {
@@ -158,7 +159,7 @@ public class ScanManager {
}
}
- public ScanManager(
+ ScanManager(
AdapterService adapterService,
ScanController scanController,
BluetoothAdapterProxy bluetoothAdapterProxy,
@@ -202,9 +203,10 @@ public class ScanManager {
IntentFilter locationIntentFilter = new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
locationIntentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mAdapterService.registerReceiver(mLocationReceiver, locationIntentFilter);
+ mBatchScanThrottler = new BatchScanThrottler(timeProvider, mScreenOn);
}
- public void cleanup() {
+ void cleanup() {
mRegularScanClients.clear();
mBatchClients.clear();
mSuspendedScanClients.clear();
@@ -233,16 +235,16 @@ public class ScanManager {
}
}
- public void registerScanner(UUID uuid) {
+ void registerScanner(UUID uuid) {
mScanNative.registerScanner(uuid.getLeastSignificantBits(), uuid.getMostSignificantBits());
}
- public void unregisterScanner(int scannerId) {
+ void unregisterScanner(int scannerId) {
mScanNative.unregisterScanner(scannerId);
}
/** Returns the regular scan queue. */
- public Set<ScanClient> getRegularScanQueue() {
+ Set<ScanClient> getRegularScanQueue() {
return mRegularScanClients;
}
@@ -252,12 +254,12 @@ public class ScanManager {
}
/** Returns batch scan queue. */
- public Set<ScanClient> getBatchScanQueue() {
+ Set<ScanClient> getBatchScanQueue() {
return mBatchClients;
}
/** Returns a set of full batch scan clients. */
- public Set<ScanClient> getFullBatchScanQueue() {
+ Set<ScanClient> getFullBatchScanQueue() {
// TODO: split full batch scan clients and truncated batch clients so we don't need to
// construct this every time.
Set<ScanClient> fullBatchClients = new HashSet<ScanClient>();
@@ -269,12 +271,12 @@ public class ScanManager {
return fullBatchClients;
}
- public void startScan(ScanClient client) {
+ void startScan(ScanClient client) {
Log.d(TAG, "startScan() " + client);
sendMessage(MSG_START_BLE_SCAN, client);
}
- public void stopScan(int scannerId) {
+ void stopScan(int scannerId) {
ScanClient client = mScanNative.getBatchScanClient(scannerId);
if (client == null) {
client = mScanNative.getRegularScanClient(scannerId);
@@ -285,14 +287,18 @@ public class ScanManager {
sendMessage(MSG_STOP_BLE_SCAN, client);
}
- public void flushBatchScanResults(ScanClient client) {
+ void flushBatchScanResults(ScanClient client) {
sendMessage(MSG_FLUSH_BATCH_RESULTS, client);
}
- public void callbackDone(int scannerId, int status) {
+ void callbackDone(int scannerId, int status) {
mScanNative.callbackDone(scannerId, status);
}
+ void batchScanResultDelivered() {
+ mBatchScanThrottler.resetBackoff();
+ }
+
private void sendMessage(int what, ScanClient client) {
mHandler.obtainMessage(what, client).sendToTarget();
}
@@ -305,10 +311,16 @@ public class ScanManager {
return mBluetoothAdapterProxy.isOffloadedScanFilteringSupported();
}
- public boolean isAutoBatchScanClientEnabled(ScanClient client) {
+ boolean isAutoBatchScanClientEnabled(ScanClient client) {
return mScanNative.isAutoBatchScanClientEnabled(client);
}
+ int getCurrentUsedTrackingAdvertisement() {
+ synchronized (mCurUsedTrackableAdvertisementsLock) {
+ return mCurUsedTrackableAdvertisements;
+ }
+ }
+
// Handler class that handles BLE scan operations.
@VisibleForTesting
class ClientHandler extends Handler {
@@ -534,6 +546,7 @@ public class ScanManager {
}
mScreenOn = false;
Log.d(TAG, "handleScreenOff()");
+ mBatchScanThrottler.onScreenOn(false);
handleSuspendScans();
updateRegularScanClientsScreenOff();
updateRegularScanToBatchScanClients();
@@ -864,6 +877,7 @@ public class ScanManager {
}
mScreenOn = true;
Log.d(TAG, "handleScreenOn()");
+ mBatchScanThrottler.onScreenOn(true);
updateBatchScanToRegularScanClients();
handleResumeScans();
updateRegularScanClientsScreenOn();
@@ -921,14 +935,14 @@ public class ScanManager {
/** Parameters for batch scans. */
static class BatchScanParams {
- public int scanMode;
- public int fullScanscannerId;
- public int truncatedScanscannerId;
+ @VisibleForTesting int mScanMode;
+ private int mFullScanscannerId;
+ private int mTruncatedScanscannerId;
BatchScanParams() {
- scanMode = -1;
- fullScanscannerId = -1;
- truncatedScanscannerId = -1;
+ mScanMode = -1;
+ mFullScanscannerId = -1;
+ mTruncatedScanscannerId = -1;
}
@Override
@@ -939,20 +953,14 @@ public class ScanManager {
if (!(obj instanceof BatchScanParams other)) {
return false;
}
- return scanMode == other.scanMode
- && fullScanscannerId == other.fullScanscannerId
- && truncatedScanscannerId == other.truncatedScanscannerId;
+ return mScanMode == other.mScanMode
+ && mFullScanscannerId == other.mFullScanscannerId
+ && mTruncatedScanscannerId == other.mTruncatedScanscannerId;
}
@Override
public int hashCode() {
- return Objects.hash(scanMode, fullScanscannerId, truncatedScanscannerId);
- }
- }
-
- public int getCurrentUsedTrackingAdvertisement() {
- synchronized (mCurUsedTrackableAdvertisementsLock) {
- return mCurUsedTrackableAdvertisements;
+ return Objects.hash(mScanMode, mFullScanscannerId, mTruncatedScanscannerId);
}
}
@@ -1262,9 +1270,9 @@ public class ScanManager {
waitForCallback();
resetCountDownLatch();
int scanInterval =
- Utils.millsToUnit(getBatchScanIntervalMillis(batchScanParams.scanMode));
+ Utils.millsToUnit(getBatchScanIntervalMillis(batchScanParams.mScanMode));
int scanWindow =
- Utils.millsToUnit(getBatchScanWindowMillis(batchScanParams.scanMode));
+ Utils.millsToUnit(getBatchScanWindowMillis(batchScanParams.mScanMode));
mNativeInterface.gattClientStartBatchScan(
scannerId,
resultType,
@@ -1298,15 +1306,15 @@ public class ScanManager {
BatchScanParams params = new BatchScanParams();
ScanClient winner = getAggressiveClient(mBatchClients);
if (winner != null) {
- params.scanMode = winner.settings.getScanMode();
+ params.mScanMode = winner.settings.getScanMode();
}
// TODO: split full batch scan results and truncated batch scan results to different
// collections.
for (ScanClient client : mBatchClients) {
if (client.settings.getScanResultType() == ScanSettings.SCAN_RESULT_TYPE_FULL) {
- params.fullScanscannerId = client.scannerId;
+ params.mFullScanscannerId = client.scannerId;
} else {
- params.truncatedScanscannerId = client.scannerId;
+ params.mTruncatedScanscannerId = client.scannerId;
}
}
return params;
@@ -1359,7 +1367,10 @@ public class ScanManager {
if (mBatchClients.isEmpty()) {
return;
}
- long batchTriggerIntervalMillis = getBatchTriggerIntervalMillis();
+ long batchTriggerIntervalMillis =
+ Flags.batchScanOptimization()
+ ? mBatchScanThrottler.getBatchTriggerIntervalMillis(mBatchClients)
+ : getBatchTriggerIntervalMillis();
// Allows the alarm to be triggered within
// [batchTriggerIntervalMillis, 1.1 * batchTriggerIntervalMillis]
long windowLengthMillis = batchTriggerIntervalMillis / 10;
@@ -1494,16 +1505,16 @@ public class ScanManager {
void flushBatchResults(int scannerId) {
Log.d(TAG, "flushPendingBatchResults - scannerId = " + scannerId);
- if (mBatchScanParams.fullScanscannerId != -1) {
+ if (mBatchScanParams.mFullScanscannerId != -1) {
resetCountDownLatch();
mNativeInterface.gattClientReadScanReports(
- mBatchScanParams.fullScanscannerId, SCAN_RESULT_TYPE_FULL);
+ mBatchScanParams.mFullScanscannerId, SCAN_RESULT_TYPE_FULL);
waitForCallback();
}
- if (mBatchScanParams.truncatedScanscannerId != -1) {
+ if (mBatchScanParams.mTruncatedScanscannerId != -1) {
resetCountDownLatch();
mNativeInterface.gattClientReadScanReports(
- mBatchScanParams.truncatedScanscannerId, SCAN_RESULT_TYPE_TRUNCATED);
+ mBatchScanParams.mTruncatedScanscannerId, SCAN_RESULT_TYPE_TRUNCATED);
waitForCallback();
}
setBatchAlarm();
@@ -1662,13 +1673,13 @@ public class ScanManager {
/** Return batch scan result type value defined in bt stack. */
private int getResultType(BatchScanParams params) {
- if (params.fullScanscannerId != -1 && params.truncatedScanscannerId != -1) {
+ if (params.mFullScanscannerId != -1 && params.mTruncatedScanscannerId != -1) {
return SCAN_RESULT_TYPE_BOTH;
}
- if (params.truncatedScanscannerId != -1) {
+ if (params.mTruncatedScanscannerId != -1) {
return SCAN_RESULT_TYPE_TRUNCATED;
}
- if (params.fullScanscannerId != -1) {
+ if (params.mFullScanscannerId != -1) {
return SCAN_RESULT_TYPE_FULL;
}
return -1;
diff --git a/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java b/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java
index 17b8d0fac9..b49eee0a03 100644
--- a/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java
+++ b/android/app/src/com/android/bluetooth/tbs/TbsGeneric.java
@@ -828,6 +828,20 @@ public class TbsGeneric {
return;
}
+ if (shouldBlockTbsForBroadcastReceiver(device)) {
+ Log.w(
+ TAG,
+ "Blocking TBS operation for non-primary device in broadcast,"
+ + " opcode = "
+ + callControlRequestOpcodeStr(opcode));
+ mTbsGatt.setCallControlPointResult(
+ device,
+ opcode,
+ 0,
+ TbsGatt.CALL_CONTROL_POINT_RESULT_OPERATION_NOT_POSSIBLE);
+ return;
+ }
+
int result;
switch (opcode) {
@@ -1229,6 +1243,20 @@ public class TbsGeneric {
return false;
}
+ private boolean shouldBlockTbsForBroadcastReceiver(BluetoothDevice device) {
+ if (device == null) {
+ Log.w(TAG, "shouldBlockTbsForBroadcastReceiver: Ignore null device");
+ return false;
+ }
+ if (!isLeAudioServiceAvailable()) {
+ Log.w(TAG, "shouldBlockTbsForBroadcastReceiver: LeAudioService is not available");
+ return false;
+ }
+
+ return mLeAudioService.getLocalBroadcastReceivers().contains(device)
+ && !mLeAudioService.isPrimaryDevice(device);
+ }
+
/**
* Dump status of TBS service along with related objects
*
diff --git a/android/app/src/com/com/android/bluetooth/le_scan/BatchScanThrottler.java b/android/app/src/com/com/android/bluetooth/le_scan/BatchScanThrottler.java
new file mode 100644
index 0000000000..4fd324dcf9
--- /dev/null
+++ b/android/app/src/com/com/android/bluetooth/le_scan/BatchScanThrottler.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2025 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.
+ */
+
+package com.android.bluetooth.le_scan;
+
+import static com.android.bluetooth.le_scan.ScanController.DEFAULT_REPORT_DELAY_FLOOR;
+
+import android.provider.DeviceConfig;
+
+import com.android.bluetooth.Utils.TimeProvider;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Set;
+
+/**
+ * Throttler to reduce the number of times the Bluetooth process wakes up to check for pending batch
+ * scan results. The wake-up intervals are increased when no matching results are found and are
+ * longer when the screen is off.
+ */
+class BatchScanThrottler {
+ // Minimum batch trigger interval to check for batched results when the screen is off
+ @VisibleForTesting static final long SCREEN_OFF_MINIMUM_DELAY_FLOOR_MS = 20000L;
+ // Adjusted minimum report delay for unfiltered batch scan clients
+ @VisibleForTesting static final long UNFILTERED_DELAY_FLOOR_MS = 20000L;
+ // Adjusted minimum report delay for unfiltered batch scan clients when the screen is off
+ @VisibleForTesting static final long UNFILTERED_SCREEN_OFF_DELAY_FLOOR_MS = 60000L;
+ // Backoff stages used as multipliers for the minimum delay floor (standard or screen-off)
+ @VisibleForTesting static final int[] BACKOFF_MULTIPLIERS = {1, 1, 2, 2, 4};
+ // Start screen-off trigger interval throttling after the screen has been off for this period
+ // of time. This allows the screen-on intervals to be used for a short period of time after the
+ // screen has gone off, and avoids too much flipping between screen-off and screen-on backoffs
+ // when the screen is off for a short period of time
+ @VisibleForTesting static final long SCREEN_OFF_DELAY_MS = 60000L;
+ private final TimeProvider mTimeProvider;
+ private final long mDelayFloor;
+ private final long mScreenOffDelayFloor;
+ private int mBackoffStage = 0;
+ private long mScreenOffTriggerTime = 0L;
+ private boolean mScreenOffThrottling = false;
+
+ BatchScanThrottler(TimeProvider timeProvider, boolean screenOn) {
+ mTimeProvider = timeProvider;
+ mDelayFloor =
+ DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_BLUETOOTH,
+ "report_delay",
+ DEFAULT_REPORT_DELAY_FLOOR);
+ mScreenOffDelayFloor = Math.max(mDelayFloor, SCREEN_OFF_MINIMUM_DELAY_FLOOR_MS);
+ onScreenOn(screenOn);
+ }
+
+ void resetBackoff() {
+ mBackoffStage = 0;
+ }
+
+ void onScreenOn(boolean screenOn) {
+ if (screenOn) {
+ mScreenOffTriggerTime = 0L;
+ mScreenOffThrottling = false;
+ resetBackoff();
+ } else {
+ // Screen-off intervals to be used after the trigger time
+ mScreenOffTriggerTime = mTimeProvider.elapsedRealtime() + SCREEN_OFF_DELAY_MS;
+ }
+ }
+
+ long getBatchTriggerIntervalMillis(Set<ScanClient> batchClients) {
+ // Check if we're past the screen-off time and should be using screen-off backoff values
+ if (!mScreenOffThrottling
+ && mScreenOffTriggerTime != 0
+ && mTimeProvider.elapsedRealtime() >= mScreenOffTriggerTime) {
+ mScreenOffThrottling = true;
+ resetBackoff();
+ }
+ long unfilteredFloor =
+ mScreenOffThrottling
+ ? UNFILTERED_SCREEN_OFF_DELAY_FLOOR_MS
+ : UNFILTERED_DELAY_FLOOR_MS;
+ long intervalMillis = Long.MAX_VALUE;
+ for (ScanClient client : batchClients) {
+ if (client.settings.getReportDelayMillis() > 0) {
+ long clientIntervalMillis = client.settings.getReportDelayMillis();
+ if ((client.filters == null || client.filters.isEmpty())
+ && clientIntervalMillis < unfilteredFloor) {
+ clientIntervalMillis = unfilteredFloor;
+ }
+ intervalMillis = Math.min(intervalMillis, clientIntervalMillis);
+ }
+ }
+ int backoffIndex =
+ mBackoffStage >= BACKOFF_MULTIPLIERS.length
+ ? BACKOFF_MULTIPLIERS.length - 1
+ : mBackoffStage++;
+ return Math.max(
+ intervalMillis,
+ (mScreenOffThrottling ? mScreenOffDelayFloor : mDelayFloor)
+ * BACKOFF_MULTIPLIERS[backoffIndex]);
+ }
+}
diff --git a/android/app/tests/unit/Android.bp b/android/app/tests/unit/Android.bp
index 346c57fffa..eae8e4a89f 100644
--- a/android/app/tests/unit/Android.bp
+++ b/android/app/tests/unit/Android.bp
@@ -22,6 +22,7 @@ java_defaults {
static_libs: [
"PlatformProperties",
+ "TestParameterInjector",
"android.media.audio-aconfig-exported-java",
"androidx.media_media",
"androidx.room_room-migration",
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java
index cd9ad4dd9a..b3d61e33af 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java
@@ -40,7 +40,6 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
@@ -75,7 +74,6 @@ public class BrowserPlayerWrapperTest {
private HandlerThread mThread;
@Mock Context mMockContext;
- @Mock Resources mMockResources;
private Context mTargetContext;
private Resources mTestResources;
private MockContentResolver mTestContentResolver;
@@ -116,8 +114,7 @@ public class BrowserPlayerWrapperTest {
});
when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
- when(mMockContext.getResources()).thenReturn(mMockResources);
+ Util.sUriImagesSupport = true;
// Set up Looper thread for the timeout handler
mThread = new HandlerThread("MediaPlayerWrapperTestThread");
@@ -138,6 +135,7 @@ public class BrowserPlayerWrapperTest {
mTestBitmap = null;
mTestResources = null;
mTargetContext = null;
+ Util.sUriImagesSupport = false;
}
private Bitmap loadImage(int resId) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java
index 60ca5a5aef..6c6e6e78fc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/ImageTest.java
@@ -36,7 +36,6 @@ import android.test.mock.MockContentResolver;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
@@ -57,7 +56,6 @@ public class ImageTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
private @Mock Context mMockContext;
- private @Mock Resources mMockResources;
private Resources mTestResources;
private MockContentResolver mTestContentResolver;
@@ -108,8 +106,7 @@ public class ImageTest {
});
when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver);
- when(mMockContext.getResources()).thenReturn(mMockResources);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
+ Util.sUriImagesSupport = true;
}
@After
@@ -119,6 +116,7 @@ public class ImageTest {
mTestResources = null;
mTargetContext = null;
mMockContext = null;
+ Util.sUriImagesSupport = false;
}
private Bitmap loadImage(int resId) {
@@ -287,7 +285,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromMediaMetadataWithArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata metadata =
getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, metadata);
@@ -302,7 +300,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromMediaMetadataWithAlbumArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata metadata =
getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, metadata);
@@ -317,7 +315,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromMediaMetadataWithDisplayIconUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata metadata =
getMediaMetadataWithUri(
MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_STRING_1);
@@ -459,7 +457,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromBundleWithArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, bundle);
assertThat(artwork.getImage()).isNull();
@@ -473,7 +471,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromBundleWithAlbumArtUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, bundle);
assertThat(artwork.getImage()).isNull();
@@ -487,7 +485,7 @@ public class ImageTest {
*/
@Test
public void testCreateImageFromBundleWithDisplayIconUriDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle =
getBundleWithUri(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_STRING_1);
Image artwork = new Image(mMockContext, bundle);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java
index 2b323d9810..794a1200b3 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MediaPlayerWrapperTest.java
@@ -36,9 +36,9 @@ import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -75,7 +75,6 @@ public class MediaPlayerWrapperTest {
@Mock MediaController mMockController;
@Mock MediaPlayerWrapper.Callback mTestCbs;
@Mock Context mMockContext;
- @Mock Resources mMockResources;
List<MediaSession.QueueItem> getQueueFromDescriptions(
List<MediaDescription.Builder> descriptions) {
@@ -98,8 +97,7 @@ public class MediaPlayerWrapperTest {
InstrumentationRegistry.getInstrumentation().getTargetContext());
mTestBitmap = loadImage(com.android.bluetooth.tests.R.raw.image_200_200);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
- when(mMockContext.getResources()).thenReturn(mMockResources);
+ Util.sUriImagesSupport = true;
// Set failure handler to capture Log.wtf messages
Log.setWtfHandler(mFailHandler);
@@ -160,6 +158,14 @@ public class MediaPlayerWrapperTest {
MediaPlayerWrapper.sTesting = true;
}
+ @After
+ public void tearDown() {
+ if (mThread != null) {
+ mThread.quitSafely();
+ }
+ Util.sUriImagesSupport = false;
+ }
+
private Bitmap loadImage(int resId) {
InputStream imageInputStream = mTestResources.openRawResource(resId);
return BitmapFactory.decodeStream(imageInputStream);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java
index 5ba6e0f4e5..4cc12f763d 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/audio_util/MetadataTest.java
@@ -38,7 +38,6 @@ import android.test.mock.MockContentResolver;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.R;
import com.android.bluetooth.TestUtils;
import org.junit.After;
@@ -59,7 +58,6 @@ public class MetadataTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
private @Mock Context mMockContext;
- private @Mock Resources mMockResources;
private Resources mTestResources;
private MockContentResolver mTestContentResolver;
@@ -111,8 +109,7 @@ public class MetadataTest {
});
when(mMockContext.getContentResolver()).thenReturn(mTestContentResolver);
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(true);
- when(mMockContext.getResources()).thenReturn(mMockResources);
+ Util.sUriImagesSupport = true;
mSongImage = new Image(mMockContext, mTestBitmap);
}
@@ -125,6 +122,7 @@ public class MetadataTest {
mTestResources = null;
mTargetContext = null;
mMockContext = null;
+ Util.sUriImagesSupport = false;
}
private Bitmap loadImage(int resId) {
@@ -427,7 +425,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromMediaMetadataWithUriAndUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaMetadata m = getMediaMetadataWithUri(MediaMetadata.METADATA_KEY_ART_URI, IMAGE_URI_1);
Metadata metadata =
new Metadata.Builder().useContext(mMockContext).fromMediaMetadata(m).build();
@@ -737,7 +735,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromBundleWithUriAndUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
Bundle bundle = getBundleWithUri(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, IMAGE_URI_1);
Metadata metadata =
new Metadata.Builder().useContext(mMockContext).fromBundle(bundle).build();
@@ -852,7 +850,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromMediaItemWithIconUriAndUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaDescription description = getMediaDescription(null, IMAGE_URI_1, null);
MediaItem item = getMediaItem(description);
Metadata metadata =
@@ -980,7 +978,7 @@ public class MetadataTest {
*/
@Test
public void testBuildMetadataFromQueueItemWithIconUriandUrisDisabled() {
- when(mMockResources.getBoolean(R.bool.avrcp_target_cover_art_uri_images)).thenReturn(false);
+ Util.sUriImagesSupport = false;
MediaDescription description = getMediaDescription(null, IMAGE_URI_1, null);
QueueItem queueItem = getQueueItem(description);
Metadata metadata =
diff --git a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java
index 2749dd7e09..c1c7734f2e 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/bass_client/BassClientServiceTest.java
@@ -4472,6 +4472,8 @@ public class BassClientServiceTest {
// Verify getSyncedBroadcastSinks returns empty device list if no broadcst ID
assertThat(mBassClientService.getSyncedBroadcastSinks().isEmpty()).isTrue();
+ assertThat(mBassClientService.getSyncedBroadcastSinks(TEST_BROADCAST_ID).isEmpty())
+ .isTrue();
// Update receiver state with broadcast ID
injectRemoteSourceStateChanged(meta, true, false);
@@ -4487,6 +4489,16 @@ public class BassClientServiceTest {
assertThat(mBassClientService.getSyncedBroadcastSinks().isEmpty()).isTrue();
}
+ activeSinks.clear();
+ // Verify getSyncedBroadcastSinks by broadcast id
+ activeSinks = mBassClientService.getSyncedBroadcastSinks(TEST_BROADCAST_ID);
+ if (Flags.leaudioBigDependsOnAudioState()) {
+ // Verify getSyncedBroadcastSinks returns correct device list if no BIS synced
+ assertThat(activeSinks.size()).isEqualTo(2);
+ assertThat(activeSinks.contains(mCurrentDevice)).isTrue();
+ assertThat(activeSinks.contains(mCurrentDevice1)).isTrue();
+ }
+
// Update receiver state with BIS sync
injectRemoteSourceStateChanged(meta, true, true);
@@ -6348,7 +6360,8 @@ public class BassClientServiceTest {
@Test
@EnableFlags({
Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER,
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE
+ Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE,
+ Flags.FLAG_LEAUDIO_MONITOR_UNICAST_SOURCE_WHEN_MANAGED_BY_BROADCAST_DELEGATOR
})
public void sinkUnintentional_handleUnicastSourceStreamStatusChange_withoutScanning() {
sinkUnintentionalWithoutScanning();
@@ -6357,7 +6370,6 @@ public class BassClientServiceTest {
mBassClientService.handleUnicastSourceStreamStatusChange(
0 /* STATUS_LOCAL_STREAM_REQUESTED */);
verifyStopBigMonitoringWithUnsync();
- verifyRemoveMessageAndInjectSourceRemoval();
checkNoResumeSynchronizationByBig();
/* Unicast finished streaming */
@@ -6370,7 +6382,8 @@ public class BassClientServiceTest {
@Test
@EnableFlags({
Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER,
- Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE
+ Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE,
+ Flags.FLAG_LEAUDIO_MONITOR_UNICAST_SOURCE_WHEN_MANAGED_BY_BROADCAST_DELEGATOR
})
public void sinkUnintentional_handleUnicastSourceStreamStatusChange_duringScanning() {
sinkUnintentionalDuringScanning();
@@ -6379,7 +6392,6 @@ public class BassClientServiceTest {
mBassClientService.handleUnicastSourceStreamStatusChange(
0 /* STATUS_LOCAL_STREAM_REQUESTED */);
verifyStopBigMonitoringWithoutUnsync();
- verifyRemoveMessageAndInjectSourceRemoval();
checkNoResumeSynchronizationByBig();
/* Unicast finished streaming */
@@ -6642,6 +6654,44 @@ public class BassClientServiceTest {
@Test
@EnableFlags({
Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER,
+ Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE,
+ Flags.FLAG_LEAUDIO_BROADCAST_ASSISTANT_PERIPHERAL_ENTRUSTMENT,
+ Flags.FLAG_LEAUDIO_MONITOR_UNICAST_SOURCE_WHEN_MANAGED_BY_BROADCAST_DELEGATOR
+ })
+ public void hostIntentional_handleUnicastSourceStreamStatusChange_beforeResumeCompleted() {
+ prepareSynchronizedPairAndStopSearching();
+
+ /* Unicast would like to stream */
+ mBassClientService.handleUnicastSourceStreamStatusChange(
+ 0 /* STATUS_LOCAL_STREAM_REQUESTED */);
+ checkNoSinkPause();
+
+ /* Unicast finished streaming */
+ mBassClientService.handleUnicastSourceStreamStatusChange(
+ 2 /* STATUS_LOCAL_STREAM_SUSPENDED */);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), any(), anyInt(), anyInt(), any(), any());
+
+ /* Unicast would like to stream again before previous resume was complete*/
+ mBassClientService.handleUnicastSourceStreamStatusChange(
+ 0 /* STATUS_LOCAL_STREAM_REQUESTED */);
+
+ /* Unicast finished streaming */
+ mBassClientService.handleUnicastSourceStreamStatusChange(
+ 2 /* STATUS_LOCAL_STREAM_SUSPENDED */);
+ mInOrderMethodProxy
+ .verify(mMethodProxy)
+ .periodicAdvertisingManagerRegisterSync(
+ any(), any(), anyInt(), anyInt(), any(), any());
+ onSyncEstablished(mSourceDevice, TEST_SYNC_HANDLE); // In case of add source to inactive
+ verifyAllGroupMembersGettingUpdateOrAddSource(createBroadcastMetadata(TEST_BROADCAST_ID));
+ }
+
+ @Test
+ @EnableFlags({
+ Flags.FLAG_LEAUDIO_BROADCAST_RESYNC_HELPER,
Flags.FLAG_LEAUDIO_BROADCAST_EXTRACT_PERIODIC_SCANNER_FROM_STATE_MACHINE
})
public void hostIntentional_handleUnicastSourceStreamStatusChangeNoContext_withoutScanning() {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java
index cc40c6af72..e274ac6eed 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/btservice/BondStateMachineTest.java
@@ -218,7 +218,7 @@ public class BondStateMachineTest {
RemoteDevices.DeviceProperties testDeviceProperties =
mRemoteDevices.addDeviceProperties(TEST_BT_ADDR_BYTES);
- testDeviceProperties.mUuids = TEST_UUIDS;
+ testDeviceProperties.mUuidsBrEdr = TEST_UUIDS;
BluetoothDevice testDevice = testDeviceProperties.getDevice();
assertThat(testDevice).isNotNull();
@@ -228,7 +228,7 @@ public class BondStateMachineTest {
bondingMsg.arg2 = AbstractionLayer.BT_STATUS_RMT_DEV_DOWN;
mBondStateMachine.sendMessage(bondingMsg);
- pendingDeviceProperties.mUuids = TEST_UUIDS;
+ pendingDeviceProperties.mUuidsBrEdr = TEST_UUIDS;
Message uuidUpdateMsg = mBondStateMachine.obtainMessage(BondStateMachine.UUID_UPDATE);
uuidUpdateMsg.obj = pendingDevice;
@@ -634,7 +634,7 @@ public class BondStateMachineTest {
}
if (uuids != null) {
// Add dummy UUID for the device.
- mDeviceProperties.mUuids = TEST_UUIDS;
+ mDeviceProperties.mUuidsBrEdr = TEST_UUIDS;
}
testSendIntentCase(
oldState,
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java
index 3a0abb2870..1eca1e2483 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java
@@ -16,6 +16,8 @@
package com.android.bluetooth.gatt;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -54,6 +56,13 @@ public class AdvertiseBinderTest {
@Before
public void setUp() {
+ doAnswer(
+ invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ })
+ .when(mAdvertiseManager)
+ .doOnAdvertiseThread(any());
mBinder = new AdvertiseBinder(mAdapterService, mAdvertiseManager);
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java
index 6621a43331..4cd5423ce9 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseManagerTest.java
@@ -27,15 +27,16 @@ import android.bluetooth.le.AdvertisingSetParameters;
import android.bluetooth.le.IAdvertisingSetCallback;
import android.bluetooth.le.PeriodicAdvertisingParameters;
import android.os.IBinder;
+import android.os.test.TestLooper;
+import android.platform.test.flag.junit.FlagsParameterization;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
+import com.android.bluetooth.flags.Flags;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -44,17 +45,21 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
+import java.util.List;
+
/** Test cases for {@link AdvertiseManager}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(ParameterizedAndroidJunit4.class)
public class AdvertiseManagerTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+ @Rule public final SetFlagsRule mSetFlagsRule;
@Mock private AdapterService mAdapterService;
- @Mock private GattService mService;
-
@Mock private AdvertiserMap mAdvertiserMap;
@Mock private AdvertiseManagerNativeInterface mNativeInterface;
@@ -66,10 +71,23 @@ public class AdvertiseManagerTest {
private AdvertiseManager mAdvertiseManager;
private int mAdvertiserId;
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.allCombinationsOf(Flags.FLAG_ADVERTISE_THREAD);
+ }
+
+ public AdvertiseManagerTest(FlagsParameterization flags) {
+ mSetFlagsRule = new SetFlagsRule(flags);
+ }
+
@Before
public void setUp() throws Exception {
- TestUtils.setAdapterService(mAdapterService);
- mAdvertiseManager = new AdvertiseManager(mService, mNativeInterface, mAdvertiserMap);
+ mAdvertiseManager =
+ new AdvertiseManager(
+ mAdapterService,
+ new TestLooper().getLooper(),
+ mNativeInterface,
+ mAdvertiserMap);
AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().build();
AdvertiseData advertiseData = new AdvertiseData.Builder().build();
@@ -95,12 +113,7 @@ public class AdvertiseManagerTest {
mCallback,
InstrumentationRegistry.getTargetContext().getAttributionSource());
- mAdvertiserId = AdvertiseManager.sTempRegistrationId;
- }
-
- @After
- public void tearDown() throws Exception {
- TestUtils.clearAdapterService(mAdapterService);
+ mAdvertiserId = mAdvertiseManager.mTempRegistrationId;
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
index f14884bcb8..b7a9a49116 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -47,6 +48,7 @@ import android.media.AudioManager;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.platform.test.annotations.EnableFlags;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
@@ -1296,6 +1298,54 @@ public class HeadsetServiceTest {
assertThat(mHeadsetService.isInbandRingingEnabled()).isFalse();
}
+ @Test
+ @EnableFlags({Flags.FLAG_UPDATE_ACTIVE_DEVICE_IN_BAND_RINGTONE})
+ public void testIncomingCallDeviceConnect_InbandRingStatus() {
+ when(mDatabaseManager.getProfileConnectionPolicy(
+ any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
+ .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
+ mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
+ connectDeviceHelper(mCurrentDevice);
+
+ when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
+ when(mStateMachines.get(mCurrentDevice).getConnectionState())
+ .thenReturn(BluetoothProfile.STATE_CONNECTED);
+
+ when(mSystemInterface.isRinging()).thenReturn(true);
+ mHeadsetService.setActiveDevice(mCurrentDevice);
+
+ verify(mNativeInterface).setActiveDevice(mCurrentDevice);
+ verify(mStateMachines.get(mCurrentDevice))
+ .sendMessage(HeadsetStateMachine.CONNECT_AUDIO, mCurrentDevice);
+ verify(mStateMachines.get(mCurrentDevice))
+ .sendMessage(eq(HeadsetStateMachine.SEND_BSIR), eq(1));
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_UPDATE_ACTIVE_DEVICE_IN_BAND_RINGTONE})
+ public void testIncomingCallWithDeviceAudioConnected() {
+ ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
+ when(mDatabaseManager.getProfileConnectionPolicy(
+ any(BluetoothDevice.class), eq(BluetoothProfile.HEADSET)))
+ .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
+ for (int i = 2; i >= 0; i--) {
+ mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
+ connectDeviceHelper(mCurrentDevice);
+ connectedDevices.add(mCurrentDevice);
+ }
+
+ mHeadsetService.setActiveDevice(connectedDevices.get(1));
+ when(mStateMachines.get(connectedDevices.get(1)).getAudioState())
+ .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
+
+ when(mSystemInterface.isRinging()).thenReturn(true);
+ mHeadsetService.setActiveDevice(connectedDevices.get(2));
+
+ verify(mNativeInterface).setActiveDevice(connectedDevices.get(2));
+ verify(mStateMachines.get(connectedDevices.get(2)), atLeast(1))
+ .sendMessage(eq(HeadsetStateMachine.SEND_BSIR), eq(0));
+ }
+
private void addConnectedDeviceHelper(BluetoothDevice device) {
mCurrentDevice = device;
when(mDatabaseManager.getProfileConnectionPolicy(
@@ -1329,4 +1379,19 @@ public class HeadsetServiceTest {
.thenReturn(priority);
assertThat(mHeadsetService.okToAcceptConnection(device, false)).isEqualTo(expected);
}
+
+ private void connectDeviceHelper(BluetoothDevice device) {
+ assertThat(mHeadsetService.connect(device)).isTrue();
+ verify(mObjectsFactory)
+ .makeStateMachine(
+ device,
+ mHeadsetService.getStateMachinesThreadLooper(),
+ mHeadsetService,
+ mAdapterService,
+ mNativeInterface,
+ mSystemInterface);
+ when(mStateMachines.get(device).getDevice()).thenReturn(device);
+ when(mStateMachines.get(device).getConnectionState())
+ .thenReturn(BluetoothProfile.STATE_CONNECTED);
+ }
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java
index e594c924a8..0b42a50d92 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetStateMachineTest.java
@@ -1793,28 +1793,6 @@ public class HeadsetStateMachineTest {
}
@Test
- @EnableFlags({Flags.FLAG_HFP_ALLOW_VOLUME_CHANGE_WITHOUT_SCO})
- public void testVolumeChangeEvent_fromIntentWhenConnected() {
- setUpConnectedState();
- int originalVolume = mHeadsetStateMachine.mSpeakerVolume;
- mHeadsetStateMachine.mSpeakerVolume = 0;
- int vol = 10;
-
- // Send INTENT_SCO_VOLUME_CHANGED message
- Intent volumeChange = new Intent(AudioManager.ACTION_VOLUME_CHANGED);
- volumeChange.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, vol);
-
- mHeadsetStateMachine.sendMessage(
- HeadsetStateMachine.INTENT_SCO_VOLUME_CHANGED, volumeChange);
- TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper());
-
- // verify volume processed
- verify(mNativeInterface).setVolume(mTestDevice, HeadsetHalConstants.VOLUME_TYPE_SPK, vol);
-
- mHeadsetStateMachine.mSpeakerVolume = originalVolume;
- }
-
- @Test
public void testVolumeChangeEvent_fromIntentWhenAudioOn() {
setUpAudioOnState();
int originalVolume = mHeadsetStateMachine.mSpeakerVolume;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
index 4ac2e96ce7..8433d1398c 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioBroadcastServiceTest.java
@@ -1730,6 +1730,30 @@ public class LeAudioBroadcastServiceTest {
}
}
+ @Test
+ public void testGetLocalBroadcastReceivers() {
+ int broadcastId = 243;
+ byte[] code = {0x00, 0x01, 0x00, 0x02};
+
+ synchronized (mService.mBroadcastCallbacks) {
+ mService.mBroadcastCallbacks.register(mCallbacks);
+ }
+
+ BluetoothLeAudioContentMetadata.Builder meta_builder =
+ new BluetoothLeAudioContentMetadata.Builder();
+ meta_builder.setLanguage("deu");
+ meta_builder.setProgramInfo("Subgroup broadcast info");
+ BluetoothLeAudioContentMetadata meta = meta_builder.build();
+
+ verifyBroadcastStarted(broadcastId, buildBroadcastSettingsFromMetadata(meta, code, 1));
+ when(mBassClientService.getSyncedBroadcastSinks(broadcastId)).thenReturn(List.of(mDevice));
+ assertThat(mService.getLocalBroadcastReceivers().size()).isEqualTo(1);
+ assertThat(mService.getLocalBroadcastReceivers()).containsExactly(mDevice);
+
+ verifyBroadcastStopped(broadcastId);
+ assertThat(mService.getLocalBroadcastReceivers()).isEmpty();
+ }
+
private class LeAudioIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index 312a031f82..4fea856b9b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -1243,8 +1243,6 @@ public class LeAudioServiceTest {
int groupId = 1;
/* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
int direction = 1;
- int snkAudioLocation = 3;
- int srcAudioLocation = 4;
int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;
// Not connected device
@@ -1254,15 +1252,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
// Add location support
- LeAudioStackEvent audioConfChangedEvent =
- new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
- audioConfChangedEvent.device = mSingleDevice;
- audioConfChangedEvent.valueInt1 = direction;
- audioConfChangedEvent.valueInt2 = groupId;
- audioConfChangedEvent.valueInt3 = snkAudioLocation;
- audioConfChangedEvent.valueInt4 = srcAudioLocation;
- audioConfChangedEvent.valueInt5 = availableContexts;
- mService.messageFromNative(audioConfChangedEvent);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -1293,8 +1283,6 @@ public class LeAudioServiceTest {
int groupId = 1;
/* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
int direction = 1;
- int snkAudioLocation = 3;
- int srcAudioLocation = 4;
int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;
// Not connected device
@@ -1304,15 +1292,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
// Add location support
- LeAudioStackEvent audioConfChangedEvent =
- new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
- audioConfChangedEvent.device = mSingleDevice;
- audioConfChangedEvent.valueInt1 = direction;
- audioConfChangedEvent.valueInt2 = groupId;
- audioConfChangedEvent.valueInt3 = snkAudioLocation;
- audioConfChangedEvent.valueInt4 = srcAudioLocation;
- audioConfChangedEvent.valueInt5 = availableContexts;
- mService.messageFromNative(audioConfChangedEvent);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -1357,8 +1337,6 @@ public class LeAudioServiceTest {
/* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
/* AUDIO_DIRECTION_INPUT_BIT = 0x02 */
int direction = 3;
- int snkAudioLocation = 3;
- int srcAudioLocation = 4;
int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;
ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor =
@@ -1372,15 +1350,7 @@ public class LeAudioServiceTest {
connectTestDevice(mRightDevice, groupId);
// Add location support
- LeAudioStackEvent audioConfChangedEvent =
- new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
- audioConfChangedEvent.device = mSingleDevice;
- audioConfChangedEvent.valueInt1 = direction;
- audioConfChangedEvent.valueInt2 = groupId;
- audioConfChangedEvent.valueInt3 = snkAudioLocation;
- audioConfChangedEvent.valueInt4 = srcAudioLocation;
- audioConfChangedEvent.valueInt5 = availableContexts;
- mService.messageFromNative(audioConfChangedEvent);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -1426,7 +1396,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();
verify(mNativeInterface, times(0)).groupSetActive(groupId);
@@ -1453,8 +1423,8 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice_2, groupId_2);
// Add location support
- injectAudioConfChanged(groupId_1, availableContexts, direction);
- injectAudioConfChanged(groupId_2, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId_1, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId_2, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId_1);
@@ -1530,7 +1500,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, groupId_1);
// Add location support
- injectAudioConfChanged(groupId_1, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId_1, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId_1);
@@ -1577,7 +1547,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -1636,8 +1606,6 @@ public class LeAudioServiceTest {
int groupId_2 = 2;
/* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */
int direction = 1;
- int snkAudioLocation = 3;
- int srcAudioLocation = 4;
int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE;
int broadcastId = 243;
byte[] code = {0x00, 0x01, 0x00, 0x02};
@@ -1680,17 +1648,8 @@ public class LeAudioServiceTest {
broadcastStateStreamingEvent.valueInt2 = LeAudioStackEvent.BROADCAST_STATE_STREAMING;
mService.messageFromNative(broadcastStateStreamingEvent);
- injectAudioConfChanged(groupId, availableContexts, direction);
-
- LeAudioStackEvent audioConfChangedEvent =
- new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED);
- audioConfChangedEvent.device = mSingleDevice_2;
- audioConfChangedEvent.valueInt1 = direction;
- audioConfChangedEvent.valueInt2 = groupId_2;
- audioConfChangedEvent.valueInt3 = snkAudioLocation;
- audioConfChangedEvent.valueInt4 = srcAudioLocation;
- audioConfChangedEvent.valueInt5 = availableContexts;
- mService.messageFromNative(audioConfChangedEvent);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice_2, groupId_2, availableContexts, direction);
// Verify only update the fallback group and not proceed to change active
assertThat(mService.setActiveDevice(mSingleDevice_2)).isTrue();
@@ -1728,7 +1687,7 @@ public class LeAudioServiceTest {
assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
@@ -1769,14 +1728,15 @@ public class LeAudioServiceTest {
mService.messageFromNative(groupStreamStatusChangedEvent);
}
- private void injectAudioConfChanged(int groupId, Integer availableContexts, int direction) {
+ private void injectAudioConfChanged(
+ BluetoothDevice device, int groupId, Integer availableContexts, int direction) {
int snkAudioLocation = 3;
int srcAudioLocation = 4;
int eventType = LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED;
// Add device to group
LeAudioStackEvent audioConfChangedEvent = new LeAudioStackEvent(eventType);
- audioConfChangedEvent.device = mSingleDevice;
+ audioConfChangedEvent.device = device;
audioConfChangedEvent.valueInt1 = direction;
audioConfChangedEvent.valueInt2 = groupId;
audioConfChangedEvent.valueInt3 = snkAudioLocation;
@@ -1798,6 +1758,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
3);
@@ -1819,6 +1780,7 @@ public class LeAudioServiceTest {
// Remove source direction
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
1);
@@ -1840,6 +1802,7 @@ public class LeAudioServiceTest {
// remove Sink and add Source back
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
2);
@@ -1868,6 +1831,7 @@ public class LeAudioServiceTest {
public void testMessageFromNativeAudioConfChangedActiveGroup() {
connectTestDevice(mSingleDevice, testGroupId);
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
3);
@@ -1891,7 +1855,7 @@ public class LeAudioServiceTest {
Integer contexts =
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL;
- injectAudioConfChanged(testGroupId, contexts, 3);
+ injectAudioConfChanged(mSingleDevice, testGroupId, contexts, 3);
TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
}
@@ -1901,7 +1865,7 @@ public class LeAudioServiceTest {
public void testMessageFromNativeAudioConfChangedNoGroupChanged() {
connectTestDevice(mSingleDevice, testGroupId);
- injectAudioConfChanged(testGroupId, 0, 3);
+ injectAudioConfChanged(mSingleDevice, testGroupId, 0, 3);
TestUtils.waitForNoIntent(TIMEOUT_MS, mDeviceQueueMap.get(mSingleDevice));
}
@@ -1934,6 +1898,32 @@ public class LeAudioServiceTest {
assertThat(mService.mLeAudioNativeIsInitialized).isTrue();
}
+ @Test
+ public void testHealthBasedGroupAction_recommendDisable() {
+ doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class));
+ connectTestDevice(mLeftDevice, testGroupId);
+ connectTestDevice(mRightDevice, testGroupId);
+
+ LeAudioStackEvent healthBasedGroupAction =
+ new LeAudioStackEvent(
+ LeAudioStackEvent.EVENT_TYPE_HEALTH_BASED_GROUP_RECOMMENDATION);
+ healthBasedGroupAction.valueInt1 = testGroupId;
+ healthBasedGroupAction.valueInt2 = LeAudioStackEvent.HEALTH_RECOMMENDATION_ACTION_DISABLE;
+ mService.messageFromNative(healthBasedGroupAction);
+ assertThat(mService.mLeAudioNativeIsInitialized).isTrue();
+
+ verify(mDatabaseManager)
+ .setProfileConnectionPolicy(
+ mLeftDevice,
+ BluetoothProfile.LE_AUDIO,
+ BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ verify(mDatabaseManager)
+ .setProfileConnectionPolicy(
+ mRightDevice,
+ BluetoothProfile.LE_AUDIO,
+ BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
+ }
+
private void sendEventAndVerifyIntentForGroupStatusChanged(int groupId, int groupStatus) {
onGroupStatusCallbackCalled = false;
@@ -1984,6 +1974,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
3);
@@ -2044,6 +2035,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
3);
@@ -2233,6 +2225,7 @@ public class LeAudioServiceTest {
injectGroupCurrentCodecConfigChanged(testGroupId, LC3_16KHZ_CONFIG, LC3_48KHZ_CONFIG);
injectAudioConfChanged(
+ mSingleDevice,
testGroupId,
BluetoothLeAudio.CONTEXT_TYPE_MEDIA | BluetoothLeAudio.CONTEXT_TYPE_CONVERSATIONAL,
3);
@@ -2369,7 +2362,7 @@ public class LeAudioServiceTest {
assertThat(mService.setActiveDevice(leadDevice)).isFalse();
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(leadDevice)).isTrue();
@@ -2435,7 +2428,7 @@ public class LeAudioServiceTest {
assertThat(mService.setActiveDevice(leadDevice)).isFalse();
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(leadDevice)).isTrue();
@@ -2496,7 +2489,7 @@ public class LeAudioServiceTest {
ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class);
// Add location support.
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
@@ -2555,7 +2548,7 @@ public class LeAudioServiceTest {
ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class);
// Add location support.
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
TestUtils.waitForLooperToFinishScheduledTask(mService.getMainLooper());
@@ -2845,7 +2838,7 @@ public class LeAudioServiceTest {
assertThat(mService.setActiveDevice(mSingleDevice)).isFalse();
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
@@ -2879,7 +2872,7 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById.contains(mRightDevice)).isTrue();
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -2896,12 +2889,12 @@ public class LeAudioServiceTest {
reset(mNativeInterface);
/* Don't expect any change. */
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
verify(mNativeInterface, times(0)).groupSetActive(groupId);
reset(mNativeInterface);
/* Expect device to be incactive */
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
verify(mNativeInterface).groupSetActive(-1);
injectGroupStatusChange(groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE);
@@ -2916,7 +2909,7 @@ public class LeAudioServiceTest {
reset(mAudioManager);
/* Expect device to be incactive */
- injectAudioConfChanged(groupId, 1, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 1, direction);
verify(mNativeInterface).groupSetActive(groupId);
reset(mNativeInterface);
@@ -2968,7 +2961,7 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById).containsExactly(mLeftDevice, mRightDevice);
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.isGroupAvailableForStream(groupId)).isTrue();
injectAndVerifyDeviceDisconnected(mLeftDevice);
@@ -2997,7 +2990,7 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById).containsExactly(mLeftDevice, mRightDevice);
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.isGroupAvailableForStream(groupId)).isTrue();
@@ -3034,7 +3027,7 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById).containsExactly(mLeftDevice, mRightDevice);
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.isGroupAvailableForStream(groupId)).isTrue();
@@ -3045,7 +3038,7 @@ public class LeAudioServiceTest {
assertThat(mService.isAutoActiveModeEnabled(groupId)).isFalse();
injectAndVerifyDeviceConnected(mLeftDevice);
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
assertThat(mService.isAutoActiveModeEnabled(groupId)).isTrue();
@@ -3079,7 +3072,7 @@ public class LeAudioServiceTest {
List<BluetoothDevice> groupDevicesById = mService.getGroupDevices(groupId);
assertThat(groupDevicesById).containsExactly(mLeftDevice, mRightDevice);
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.isGroupAvailableForStream(groupId)).isTrue();
@@ -3090,7 +3083,7 @@ public class LeAudioServiceTest {
assertThat(mService.isAutoActiveModeEnabled(groupId)).isFalse();
injectAndVerifyDeviceConnected(mLeftDevice);
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
verify(mScanController).registerScannerInternal(scanCallbacks.capture(), any(), any());
@@ -3133,13 +3126,13 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById.contains(mRightDevice)).isTrue();
// Add location support
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isFalse();
verify(mNativeInterface, times(0)).groupSetActive(groupId);
// Expect device to be active
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
verify(mNativeInterface).groupSetActive(groupId);
@@ -3155,7 +3148,7 @@ public class LeAudioServiceTest {
reset(mNativeInterface);
// Expect device to be inactive
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
verify(mNativeInterface).groupSetActive(-1);
injectGroupStatusChange(groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE);
@@ -3170,7 +3163,7 @@ public class LeAudioServiceTest {
reset(mAudioManager);
// Expect device to be active
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
verify(mNativeInterface).groupSetActive(groupId);
reset(mNativeInterface);
@@ -3217,7 +3210,7 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById.contains(mRightDevice)).isTrue();
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -3234,7 +3227,7 @@ public class LeAudioServiceTest {
reset(mNativeInterface);
// Expect device to be inactive
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
verify(mNativeInterface).groupSetActive(-1);
injectGroupStatusChange(groupId, LeAudioStackEvent.GROUP_STATUS_INACTIVE);
@@ -3259,7 +3252,7 @@ public class LeAudioServiceTest {
assertThat(mService.getConnectedDevices().contains(mRightDevice)).isFalse();
// Expect device to be inactive
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
generateConnectionMessageFromNative(
mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);
@@ -3268,7 +3261,7 @@ public class LeAudioServiceTest {
assertThat(mService.getConnectedDevices().contains(mLeftDevice)).isTrue();
// Expect device to be inactive
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
generateConnectionMessageFromNative(
mRightDevice,
@@ -3279,7 +3272,7 @@ public class LeAudioServiceTest {
assertThat(mService.getConnectedDevices().contains(mRightDevice)).isTrue();
// Expect device to be active
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
verify(mNativeInterface).groupSetActive(groupId);
@@ -3321,7 +3314,7 @@ public class LeAudioServiceTest {
assertThat(groupDevicesById.contains(mRightDevice)).isTrue();
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mLeftDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -3347,7 +3340,7 @@ public class LeAudioServiceTest {
reset(mAudioManager);
// Expect device to be inactive
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
generateConnectionMessageFromNative(
mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);
@@ -3356,7 +3349,7 @@ public class LeAudioServiceTest {
assertThat(mService.getConnectedDevices().contains(mLeftDevice)).isTrue();
// Expect device to be inactive
- injectAudioConfChanged(groupId, 0, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, 0, direction);
generateConnectionMessageFromNative(
mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);
@@ -3365,7 +3358,7 @@ public class LeAudioServiceTest {
assertThat(mService.getConnectedDevices().contains(mRightDevice)).isTrue();
// Expect device to be active
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
verify(mNativeInterface).groupSetActive(groupId);
@@ -3395,7 +3388,7 @@ public class LeAudioServiceTest {
connectTestDevice(mSingleDevice, testGroupId);
// Add location support
- injectAudioConfChanged(groupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, groupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(groupId);
@@ -3461,7 +3454,7 @@ public class LeAudioServiceTest {
assertThat(mService.getBroadcastToUnicastFallbackGroup()).isEqualTo(firstGroupId);
// Add location support
- injectAudioConfChanged(firstGroupId, availableContexts, direction);
+ injectAudioConfChanged(mSingleDevice, firstGroupId, availableContexts, direction);
assertThat(mService.setActiveDevice(mSingleDevice)).isTrue();
verify(mNativeInterface).groupSetActive(firstGroupId);
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/BatchScanThrottlerTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/BatchScanThrottlerTest.java
new file mode 100644
index 0000000000..67f32c4f0c
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/BatchScanThrottlerTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+package com.android.bluetooth.le_scan;
+
+import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
+
+import static com.android.bluetooth.le_scan.ScanController.DEFAULT_REPORT_DELAY_FLOOR;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanSettings;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.bluetooth.TestUtils.FakeTimeProvider;
+
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.LongStream;
+
+/** Test cases for {@link BatchScanThrottler}. */
+@SmallTest
+@RunWith(TestParameterInjector.class)
+public class BatchScanThrottlerTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ private FakeTimeProvider mTimeProvider;
+
+ @Before
+ public void setUp() {
+ mTimeProvider = new FakeTimeProvider();
+ }
+
+ private void advanceTime(long amountToAdvanceMillis) {
+ mTimeProvider.advanceTime(Duration.ofMillis(amountToAdvanceMillis));
+ }
+
+ @Test
+ public void basicThrottling(
+ @TestParameter boolean isFiltered, @TestParameter boolean isScreenOn) {
+ BatchScanThrottler throttler = new BatchScanThrottler(mTimeProvider, isScreenOn);
+ if (!isScreenOn) {
+ advanceTime(BatchScanThrottler.SCREEN_OFF_DELAY_MS);
+ }
+ Set<ScanClient> clients =
+ Collections.singleton(
+ createBatchScanClient(DEFAULT_REPORT_DELAY_FLOOR, isFiltered));
+ long[] backoffIntervals =
+ getBackoffIntervals(
+ isScreenOn
+ ? DEFAULT_REPORT_DELAY_FLOOR
+ : BatchScanThrottler.SCREEN_OFF_MINIMUM_DELAY_FLOOR_MS);
+ for (long x : backoffIntervals) {
+ long expected = adjustExpectedInterval(x, isFiltered, isScreenOn);
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(expected);
+ }
+ long expected =
+ adjustExpectedInterval(
+ backoffIntervals[backoffIntervals.length - 1], isFiltered, isScreenOn);
+ // Ensure that subsequent calls continue to return the final throttled interval
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(expected);
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(expected);
+ }
+
+ @Test
+ public void screenOffDelayAndReset(@TestParameter boolean screenOnAtStart) {
+ BatchScanThrottler throttler = new BatchScanThrottler(mTimeProvider, screenOnAtStart);
+ if (screenOnAtStart) {
+ throttler.onScreenOn(false);
+ }
+ Set<ScanClient> clients =
+ Collections.singleton(createBatchScanClient(DEFAULT_REPORT_DELAY_FLOOR, true));
+ long[] backoffIntervals = getBackoffIntervals(DEFAULT_REPORT_DELAY_FLOOR);
+ advanceTime(BatchScanThrottler.SCREEN_OFF_DELAY_MS - 1);
+ for (long x : backoffIntervals) {
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(x);
+ }
+
+ backoffIntervals =
+ getBackoffIntervals(BatchScanThrottler.SCREEN_OFF_MINIMUM_DELAY_FLOOR_MS);
+ advanceTime(1);
+ for (long x : backoffIntervals) {
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(x);
+ }
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients))
+ .isEqualTo(backoffIntervals[backoffIntervals.length - 1]);
+ }
+
+ @Test
+ public void testScreenOnReset() {
+ BatchScanThrottler throttler = new BatchScanThrottler(mTimeProvider, false);
+ advanceTime(BatchScanThrottler.SCREEN_OFF_DELAY_MS);
+ Set<ScanClient> clients =
+ Collections.singleton(createBatchScanClient(DEFAULT_REPORT_DELAY_FLOOR, true));
+ long[] backoffIntervals =
+ getBackoffIntervals(BatchScanThrottler.SCREEN_OFF_MINIMUM_DELAY_FLOOR_MS);
+ for (long x : backoffIntervals) {
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(x);
+ }
+
+ throttler.onScreenOn(true);
+ backoffIntervals = getBackoffIntervals(DEFAULT_REPORT_DELAY_FLOOR);
+ for (long x : backoffIntervals) {
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(x);
+ }
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients))
+ .isEqualTo(backoffIntervals[backoffIntervals.length - 1]);
+ }
+
+ @Test
+ public void resetBackoff_restartsToFirstStage(@TestParameter boolean isScreenOn) {
+ BatchScanThrottler throttler = new BatchScanThrottler(mTimeProvider, isScreenOn);
+ if (!isScreenOn) {
+ // Advance the time before we start the test to when the screen-off intervals should be
+ // used
+ advanceTime(BatchScanThrottler.SCREEN_OFF_DELAY_MS);
+ }
+ Set<ScanClient> clients =
+ Collections.singleton(createBatchScanClient(DEFAULT_REPORT_DELAY_FLOOR, true));
+ long[] backoffIntervals =
+ getBackoffIntervals(
+ isScreenOn
+ ? DEFAULT_REPORT_DELAY_FLOOR
+ : BatchScanThrottler.SCREEN_OFF_MINIMUM_DELAY_FLOOR_MS);
+ for (long x : backoffIntervals) {
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(x);
+ }
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients))
+ .isEqualTo(backoffIntervals[backoffIntervals.length - 1]);
+
+ throttler.resetBackoff();
+ for (long x : backoffIntervals) {
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients)).isEqualTo(x);
+ }
+ assertThat(throttler.getBatchTriggerIntervalMillis(clients))
+ .isEqualTo(backoffIntervals[backoffIntervals.length - 1]);
+ }
+
+ private long adjustExpectedInterval(long interval, boolean isFiltered, boolean isScreenOn) {
+ if (isFiltered) {
+ return interval;
+ }
+ long threshold =
+ isScreenOn
+ ? BatchScanThrottler.UNFILTERED_DELAY_FLOOR_MS
+ : BatchScanThrottler.UNFILTERED_SCREEN_OFF_DELAY_FLOOR_MS;
+ return Math.max(interval, threshold);
+ }
+
+ private long[] getBackoffIntervals(long baseInterval) {
+ return LongStream.range(0, BatchScanThrottler.BACKOFF_MULTIPLIERS.length)
+ .map(x -> BatchScanThrottler.BACKOFF_MULTIPLIERS[(int) x] * baseInterval)
+ .toArray();
+ }
+
+ private ScanClient createBatchScanClient(long reportDelayMillis, boolean isFiltered) {
+ ScanSettings scanSettings =
+ new ScanSettings.Builder()
+ .setScanMode(SCAN_MODE_BALANCED)
+ .setReportDelay(reportDelayMillis)
+ .build();
+
+ return new ScanClient(1, scanSettings, createScanFilterList(isFiltered), 1);
+ }
+
+ private List<ScanFilter> createScanFilterList(boolean isFiltered) {
+ List<ScanFilter> scanFilterList = null;
+ if (isFiltered) {
+ scanFilterList = List.of(new ScanFilter.Builder().setDeviceName("TestName").build());
+ }
+ return scanFilterList;
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanControllerTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanControllerTest.java
index 2b19c1aa0b..ea051bc528 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanControllerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanControllerTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.bluetooth.BluetoothAdapter;
@@ -47,7 +48,6 @@ import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
@@ -55,6 +55,9 @@ import com.android.bluetooth.btservice.CompanionManager;
import com.android.bluetooth.gatt.GattNativeInterface;
import com.android.bluetooth.gatt.GattObjectsFactory;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -73,7 +76,7 @@ import java.util.Set;
/** Test cases for {@link ScanController}. */
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(TestParameterInjector.class)
public class ScanControllerTest {
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -187,7 +190,8 @@ public class ScanControllerTest {
}
@Test
- public void onBatchScanReportsInternal_deliverBatchScan() throws RemoteException {
+ public void onBatchScanReportsInternal_deliverBatchScan_full(
+ @TestParameter boolean expectResults) throws RemoteException {
int status = 1;
int scannerId = 2;
int reportType = ScanManager.SCAN_RESULT_TYPE_FULL;
@@ -200,28 +204,59 @@ public class ScanControllerTest {
Set<ScanClient> scanClientSet = new HashSet<>();
ScanClient scanClient = new ScanClient(scannerId);
scanClient.associatedDevices = new ArrayList<>();
- scanClient.associatedDevices.add("02:00:00:00:00:00");
scanClient.scannerId = scannerId;
+ if (expectResults) {
+ scanClient.hasScanWithoutLocationPermission = true;
+ }
scanClientSet.add(scanClient);
doReturn(scanClientSet).when(mScanManager).getFullBatchScanQueue();
doReturn(mApp).when(mScannerMap).getById(scanClient.scannerId);
+ IScannerCallback callback = mock(IScannerCallback.class);
+ mApp.mCallback = callback;
mScanController.onBatchScanReportsInternal(
status, scannerId, reportType, numRecords, recordData);
verify(mScanManager).callbackDone(scannerId, status);
+ if (expectResults) {
+ verify(callback).onBatchScanResults(any());
+ } else {
+ verify(callback, never()).onBatchScanResults(any());
+ }
+ }
- reportType = ScanManager.SCAN_RESULT_TYPE_TRUNCATED;
- recordData =
+ @Test
+ public void onBatchScanReportsInternal_deliverBatchScan_truncated(
+ @TestParameter boolean expectResults) throws RemoteException {
+ int status = 1;
+ int scannerId = 2;
+ int reportType = ScanManager.SCAN_RESULT_TYPE_TRUNCATED;
+ int numRecords = 1;
+ byte[] recordData =
new byte[] {
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x04, 0x02, 0x02, 0x00, 0x00, 0x02
};
+
+ Set<ScanClient> scanClientSet = new HashSet<>();
+ ScanClient scanClient = new ScanClient(scannerId);
+ scanClient.associatedDevices = new ArrayList<>();
+ if (expectResults) {
+ scanClient.associatedDevices.add("02:00:00:00:00:00");
+ }
+ scanClient.scannerId = scannerId;
+ scanClientSet.add(scanClient);
doReturn(scanClientSet).when(mScanManager).getBatchScanQueue();
+ doReturn(mApp).when(mScannerMap).getById(scanClient.scannerId);
IScannerCallback callback = mock(IScannerCallback.class);
mApp.mCallback = callback;
mScanController.onBatchScanReportsInternal(
status, scannerId, reportType, numRecords, recordData);
- verify(callback).onBatchScanResults(any());
+ verify(mScanManager).callbackDone(scannerId, status);
+ if (expectResults) {
+ verify(callback).onBatchScanResults(any());
+ } else {
+ verify(callback, never()).onBatchScanResults(any());
+ }
}
@Test
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java
index 25a27ce876..041a982a9b 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanManagerTest.java
@@ -1045,7 +1045,7 @@ public class ScanManagerTest {
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
assertThat(mScanManager.getBatchScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanParams().scanMode).isEqualTo(expectedScanMode);
+ assertThat(mScanManager.getBatchScanParams().mScanMode).isEqualTo(expectedScanMode);
}
}
@@ -1075,13 +1075,13 @@ public class ScanManagerTest {
sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
- assertThat(mScanManager.getBatchScanParams().scanMode).isEqualTo(expectedScanMode);
+ assertThat(mScanManager.getBatchScanParams().mScanMode).isEqualTo(expectedScanMode);
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
assertThat(mScanManager.getBatchScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanParams().scanMode).isEqualTo(expectedScanMode);
+ assertThat(mScanManager.getBatchScanParams().mScanMode).isEqualTo(expectedScanMode);
}
}
@@ -1152,7 +1152,7 @@ public class ScanManagerTest {
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
assertThat(mScanManager.getBatchScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanParams().scanMode)
+ assertThat(mScanManager.getBatchScanParams().mScanMode)
.isEqualTo(expectedScanMode);
// Turn on screen
sendMessageWaitForProcessed(createScreenOnOffMessage(true));
@@ -1166,7 +1166,7 @@ public class ScanManagerTest {
assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
assertThat(mScanManager.getBatchScanQueue()).contains(client);
- assertThat(mScanManager.getBatchScanParams().scanMode)
+ assertThat(mScanManager.getBatchScanParams().mScanMode)
.isEqualTo(expectedScanMode);
});
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGenericTest.java b/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGenericTest.java
index ddd76bb793..345dd8a5ee 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGenericTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/tbs/TbsGenericTest.java
@@ -45,6 +45,7 @@ import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -683,4 +684,80 @@ public class TbsGenericTest {
anyInt(),
eq(BluetoothLeCallControl.RESULT_SUCCESS));
}
+
+ @Test
+ public void testCallOperationsBlockedForBroadcastReceiver() {
+ Integer ccid = prepareTestBearer();
+ reset(mTbsGatt);
+
+ LeAudioService leAudioService = mock(LeAudioService.class);
+ mTbsGeneric.setLeAudioServiceForTesting(leAudioService);
+
+ // Prepare the incoming call
+ UUID callUuid = UUID.randomUUID();
+ List<BluetoothLeCall> tbsCalls = new ArrayList<>();
+ tbsCalls.add(
+ new BluetoothLeCall(
+ callUuid,
+ "tel:987654321",
+ "aFriendlyCaller",
+ BluetoothLeCall.STATE_INCOMING,
+ 0));
+ mTbsGeneric.currentCallsList(ccid, tbsCalls);
+
+ ArgumentCaptor<Map> currentCallsCaptor = ArgumentCaptor.forClass(Map.class);
+ verify(mTbsGatt).setCallState(currentCallsCaptor.capture());
+ Map<Integer, TbsCall> capturedCurrentCalls = currentCallsCaptor.getValue();
+ assertThat(capturedCurrentCalls.size()).isEqualTo(1);
+ Integer callIndex = capturedCurrentCalls.entrySet().iterator().next().getKey();
+ reset(mTbsGatt);
+
+ doReturn(new HashSet<>(Arrays.asList(mDevice)))
+ .when(leAudioService)
+ .getLocalBroadcastReceivers();
+
+ doReturn(false).when(leAudioService).isPrimaryDevice(mDevice);
+
+ // Verify call accept
+ byte args[] = new byte[1];
+ args[0] = (byte) (callIndex & 0xFF);
+ mTbsGattCallback
+ .getValue()
+ .onCallControlPointRequest(
+ mDevice, TbsGatt.CALL_CONTROL_POINT_OPCODE_ACCEPT, args);
+
+ // Active device should not be changed
+ verify(leAudioService, never()).setActiveDevice(mDevice);
+ // Verify if GTBS control point is updated to notify the peer about the result
+ verify(mTbsGatt)
+ .setCallControlPointResult(
+ eq(mDevice),
+ eq(TbsGatt.CALL_CONTROL_POINT_OPCODE_ACCEPT),
+ eq(0),
+ eq(TbsGatt.CALL_CONTROL_POINT_RESULT_OPERATION_NOT_POSSIBLE));
+
+ // Verify call terminate
+ tbsCalls.clear();
+ tbsCalls.add(
+ new BluetoothLeCall(
+ callUuid,
+ "tel:987654321",
+ "aFriendlyCaller",
+ BluetoothLeCall.STATE_ACTIVE,
+ 0));
+ mTbsGeneric.currentCallsList(ccid, tbsCalls);
+
+ mTbsGattCallback
+ .getValue()
+ .onCallControlPointRequest(
+ mDevice, TbsGatt.CALL_CONTROL_POINT_OPCODE_TERMINATE, args);
+
+ // Verify if GTBS control point is updated to notify the peer about the result
+ verify(mTbsGatt)
+ .setCallControlPointResult(
+ eq(mDevice),
+ eq(TbsGatt.CALL_CONTROL_POINT_OPCODE_TERMINATE),
+ eq(0),
+ eq(TbsGatt.CALL_CONTROL_POINT_RESULT_OPERATION_NOT_POSSIBLE));
+ }
}
diff --git a/android/pandora/mmi2grpc/mmi2grpc/_rootcanal.py b/android/pandora/mmi2grpc/mmi2grpc/_rootcanal.py
index 42ef33f68b..5f68da54f7 100644
--- a/android/pandora/mmi2grpc/mmi2grpc/_rootcanal.py
+++ b/android/pandora/mmi2grpc/mmi2grpc/_rootcanal.py
@@ -92,6 +92,7 @@ class Dongle(enum.Enum):
DEFAULT = "default"
LAIRD_BL654 = "laird_bl654"
CSR_RCK_PTS_DONGLE = "csr_rck_pts_dongle"
+ INTEL_BE200 = "intel_be200"
class RootCanal:
diff --git a/android/pandora/mmi2grpc/mmi2grpc/avrcp.py b/android/pandora/mmi2grpc/mmi2grpc/avrcp.py
index 9fbc55d56c..c64eb2113f 100644
--- a/android/pandora/mmi2grpc/mmi2grpc/avrcp.py
+++ b/android/pandora/mmi2grpc/mmi2grpc/avrcp.py
@@ -117,6 +117,7 @@ class AVRCPProxy(ProfileProxy):
Action: Make sure the IUT is in a connectable state.
"""
+ self.mediaplayer.ResetQueue()
return "OK"
@assert_description
@@ -1080,3 +1081,73 @@ class AVRCPProxy(ProfileProxy):
"""
return "OK"
+
+ @assert_description
+ def TSC_OBEX_MMI_iut_accept_slc_connect_l2cap(self, **kwargs):
+ """
+ Please accept the l2cap channel connection for an OBEX connection.
+ """
+
+ return "OK"
+
+ @assert_description
+ def TSC_OBEX_MMI_iut_accept_connect(self, **kwargs):
+ """
+ Please accept the OBEX CONNECT REQ.
+ """
+
+ return "OK"
+
+
+ @assert_description
+ def TSC_AVRCP_mmi_user_queue_cover_art_element(self, **kwargs):
+ """
+ Take action to play a media element with cover art. Press 'Ok' when
+ ready.
+ """
+ self.mediaplayer.Play()
+
+ return "OK"
+
+ @assert_description
+ def TSC_AVRCP_mmi_iut_reject_invalid_get_img(self, **kwargs):
+ """
+ Take action to reject the invalid 'get-img' request sent by the tester.
+ """
+
+ return "OK"
+
+ @assert_description
+ def TSC_BIP_MMI_iut_accept_get_img_properties(self, **kwargs):
+ """
+ Take action to accept the GetImgProperties operation from the tester.
+ """
+
+ return "OK"
+
+ @assert_description
+ def TSC_BIP_MMI_iut_accept_get_img(self, **kwargs):
+ """
+ Take action to accept the GetImg operation from the tester.
+ """
+
+ return "OK"
+
+ @assert_description
+ def TSC_OBEX_MMI_tester_verify_sent_file_or_folder(self, **kwargs):
+ """
+ Was the currently displayed file or folder sent by the IUT?
+ """
+
+ return "OK"
+
+ @assert_description
+ def TSC_AVRCP_mmi_user_queue_no_cover_art_element(self, **kwargs):
+ """
+ Take action to play a media element that does not have any cover art
+ with it. Press 'Ok' when ready.
+ """
+ self.mediaplayer.UpdateQueue()
+ self.mediaplayer.PlayUpdated()
+
+ return "OK"
diff --git a/android/pandora/server/configs/pts_bot_tests_config.json b/android/pandora/server/configs/pts_bot_tests_config.json
index 7b44a66f18..9a80a7471e 100644
--- a/android/pandora/server/configs/pts_bot_tests_config.json
+++ b/android/pandora/server/configs/pts_bot_tests_config.json
@@ -129,6 +129,11 @@
"AVDTP/SRC/INT/SIG/SMG/BV-31-C",
"AVDTP/SRC/INT/SIG/SYN/BV-05-C",
"AVDTP/SRC/INT/TRA/BTR/BV-01-C",
+ "AVRCP/TG/CA/BI-03-C",
+ "AVRCP/TG/CA/BI-05-C",
+ "AVRCP/TG/CA/BI-07-C",
+ "AVRCP/TG/CA/BI-10-C",
+ "AVRCP/TG/CA/BV-16-C",
"AVRCP/CT/CEC/BV-02-I",
"AVRCP/CT/CRC/BV-02-I",
"AVRCP/TG/CEC/BV-01-I",
@@ -769,6 +774,21 @@
"AVDTP/SRC/INT/SIG/SMG/BV-23-C",
"AVDTP/SRC/INT/SIG/SMG/BV-33-C",
"AVDTP/SRC/INT/SIG/SMG/ESR05/BV-13-C",
+ "AVRCP/TG/CA/BI-01-C",
+ "AVRCP/TG/CA/BI-04-C",
+ "AVRCP/TG/CA/BI-06-C",
+ "AVRCP/TG/CA/BI-08-C",
+ "AVRCP/TG/CA/BI-09-C",
+ "AVRCP/TG/CA/BV-01-I",
+ "AVRCP/TG/CA/BV-02-C",
+ "AVRCP/TG/CA/BV-02-I",
+ "AVRCP/TG/CA/BV-03-I",
+ "AVRCP/TG/CA/BV-04-C",
+ "AVRCP/TG/CA/BV-06-C",
+ "AVRCP/TG/CA/BV-08-C",
+ "AVRCP/TG/CA/BV-10-C",
+ "AVRCP/TG/CA/BV-12-C",
+ "AVRCP/TG/CA/BV-14-C",
"AVRCP/CT/CEC/BV-01-I",
"AVRCP/CT/CRC/BV-01-I",
"AVRCP/CT/PTH/BV-01-C",
@@ -1566,6 +1586,7 @@
"TSPC_AVRCP_7_64": true,
"TSPC_AVRCP_7_65": true,
"TSPC_AVRCP_7_66": true,
+ "TSPC_AVRCP_7_67": true,
"TSPC_AVRCP_7b_4": true,
"TSPC_AVRCP_8_19": true,
"TSPC_AVRCP_8_20": true,
@@ -3215,6 +3236,20 @@
"flags": [
{
"flags": [
+ "set_addressed_player",
+ "browsing_refactor",
+ "avrcp_16_default"
+ ],
+ "tests": [
+ "AVRCP/TG/CA/BI-03-C",
+ "AVRCP/TG/CA/BI-05-C",
+ "AVRCP/TG/CA/BI-07-C",
+ "AVRCP/TG/CA/BI-10-C",
+ "AVRCP/TG/CA/BV-16-C"
+ ]
+ },
+ {
+ "flags": [
"leaudio_allow_leaudio_only_devices",
"enable_hap_by_default"
],
diff --git a/android/pandora/server/src/A2dp.kt b/android/pandora/server/src/A2dp.kt
index 6708dd1c46..0b5a0d6640 100644
--- a/android/pandora/server/src/A2dp.kt
+++ b/android/pandora/server/src/A2dp.kt
@@ -41,7 +41,6 @@ import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
-import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filter
@@ -110,10 +109,6 @@ class A2dp(val context: Context) : A2DPImplBase(), Closeable {
}
}
- // TODO: b/234891800, AVDTP start request sometimes never sent if playback starts too
- // early.
- delay(2000L)
-
val source =
Source.newBuilder().setCookie(ByteString.copyFrom(device.getAddress(), "UTF-8"))
OpenSourceResponse.newBuilder().setSource(source).build()
@@ -147,10 +142,6 @@ class A2dp(val context: Context) : A2DPImplBase(), Closeable {
}
}
- // TODO: b/234891800, AVDTP start request sometimes never sent if playback starts too
- // early.
- delay(2000L)
-
val source =
Source.newBuilder().setCookie(ByteString.copyFrom(device.getAddress(), "UTF-8"))
WaitSourceResponse.newBuilder().setSource(source).build()
diff --git a/android/pandora/server/src/MediaPlayer.kt b/android/pandora/server/src/MediaPlayer.kt
index 81d6a8a78a..a2c981f881 100644
--- a/android/pandora/server/src/MediaPlayer.kt
+++ b/android/pandora/server/src/MediaPlayer.kt
@@ -55,6 +55,13 @@ class MediaPlayer(val context: Context) : MediaPlayerImplBase(), Closeable {
}
}
+ override fun playUpdated(request: Empty, responseObserver: StreamObserver<Empty>) {
+ grpcUnary<Empty>(scope, responseObserver) {
+ MediaPlayerBrowserService.instance.playUpdated()
+ Empty.getDefaultInstance()
+ }
+ }
+
override fun stop(request: Empty, responseObserver: StreamObserver<Empty>) {
grpcUnary<Empty>(scope, responseObserver) {
MediaPlayerBrowserService.instance.stop()
@@ -111,6 +118,13 @@ class MediaPlayer(val context: Context) : MediaPlayerImplBase(), Closeable {
}
}
+ override fun resetQueue(request: Empty, responseObserver: StreamObserver<Empty>) {
+ grpcUnary<Empty>(scope, responseObserver) {
+ MediaPlayerBrowserService.instance.resetQueue()
+ Empty.getDefaultInstance()
+ }
+ }
+
override fun getShuffleMode(
request: Empty,
responseObserver: StreamObserver<GetShuffleModeResponse>
diff --git a/android/pandora/server/src/MediaPlayerBrowserService.kt b/android/pandora/server/src/MediaPlayerBrowserService.kt
index b7a358f79c..eaab8a9bbe 100644
--- a/android/pandora/server/src/MediaPlayerBrowserService.kt
+++ b/android/pandora/server/src/MediaPlayerBrowserService.kt
@@ -17,6 +17,7 @@
package com.android.pandora
import android.content.Intent
+import android.graphics.Bitmap
import android.media.MediaPlayer
import android.os.Bundle
import android.support.v4.media.*
@@ -43,6 +44,7 @@ class MediaPlayerBrowserService : MediaBrowserServiceCompat() {
private var metadataItems = mutableMapOf<String, MediaMetadataCompat>()
private var queue = mutableListOf<MediaSessionCompat.QueueItem>()
private var currentTrack = -1
+ private val testIcon = Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888)
override fun onCreate() {
super.onCreate()
@@ -114,6 +116,12 @@ class MediaPlayerBrowserService : MediaBrowserServiceCompat() {
mediaSession.setMetadata(metadataItems.get("" + currentTrack))
}
+ fun playUpdated() {
+ currentTrack = NEW_QUEUE_ITEM_INDEX
+ setPlaybackState(PlaybackStateCompat.STATE_PLAYING)
+ mediaSession.setMetadata(metadataItems.get("" + currentTrack))
+ }
+
fun stop() {
setPlaybackState(PlaybackStateCompat.STATE_STOPPED)
mediaSession.setMetadata(null)
@@ -170,12 +178,23 @@ class MediaPlayerBrowserService : MediaBrowserServiceCompat() {
.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, NEW_QUEUE_ITEM_INDEX.toLong())
.build()
val mediaItem = MediaItem(metaData.description, MediaItem.FLAG_PLAYABLE)
+ metadataItems.put("" + NEW_QUEUE_ITEM_INDEX, metaData)
queue.add(
MediaSessionCompat.QueueItem(mediaItem.description, NEW_QUEUE_ITEM_INDEX.toLong())
)
mediaSession.setQueue(queue)
}
+ fun resetQueue() {
+ if (metadataItems.contains("" + NEW_QUEUE_ITEM_INDEX)) {
+ metadataItems.remove("" + NEW_QUEUE_ITEM_INDEX)
+ queue.removeLast()
+ mediaSession.setQueue(queue)
+ stop()
+ currentTrack = QUEUE_START_INDEX
+ }
+ }
+
fun getShuffleMode(): Int {
val controller = mediaSession.getController()
return controller.getShuffleMode()
@@ -261,6 +280,7 @@ class MediaPlayerBrowserService : MediaBrowserServiceCompat() {
)
.putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, item.toLong())
.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, QUEUE_SIZE.toLong())
+ .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, testIcon)
.build()
val mediaItem = MediaItem(metaData.description, MediaItem.FLAG_PLAYABLE)
mediaItems.add(mediaItem)
diff --git a/flags/Android.bp b/flags/Android.bp
index 8a1dc66552..80a57891a5 100644
--- a/flags/Android.bp
+++ b/flags/Android.bp
@@ -31,6 +31,7 @@ aconfig_declarations {
"hid.aconfig",
"l2cap.aconfig",
"le_advertising.aconfig",
+ "le_scanning.aconfig",
"leaudio.aconfig",
"mapclient.aconfig",
"mcp.aconfig",
diff --git a/flags/BUILD.gn b/flags/BUILD.gn
index 9f96d85933..da5aa8621b 100644
--- a/flags/BUILD.gn
+++ b/flags/BUILD.gn
@@ -24,6 +24,7 @@ aconfig("bluetooth_flags_c_lib") {
"hid.aconfig",
"l2cap.aconfig",
"le_advertising.aconfig",
+ "le_scanning.aconfig",
"leaudio.aconfig",
"mapclient.aconfig",
"mcp.aconfig",
diff --git a/flags/bta_dm.aconfig b/flags/bta_dm.aconfig
index d91f3168b7..287a0f0187 100644
--- a/flags/bta_dm.aconfig
+++ b/flags/bta_dm.aconfig
@@ -9,13 +9,6 @@ flag {
}
flag {
- name: "bta_dm_discover_both"
- namespace: "bluetooth"
- description: "perform both LE and Classic service discovery simulteanously on capable devices"
- bug: "339217881"
-}
-
-flag {
name: "cancel_open_discovery_client"
namespace: "bluetooth"
description: "Cancel connection from discovery client correctly"
diff --git a/flags/gap.aconfig b/flags/gap.aconfig
index 9b139eead2..5da5144aa1 100644
--- a/flags/gap.aconfig
+++ b/flags/gap.aconfig
@@ -271,3 +271,23 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "fix_bluetooth_gatt_getting_duplicate_services"
+ namespace: "bluetooth"
+ description: "Fixes BluetoothGatt getting duplicate GATT services"
+ bug: "391773937"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "batch_scan_optimization"
+ namespace: "bluetooth"
+ description: "Optimized batch scan for less wakeups"
+ bug: "392132489"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/hfp.aconfig b/flags/hfp.aconfig
index 7b81b483b4..026c3b22b3 100644
--- a/flags/hfp.aconfig
+++ b/flags/hfp.aconfig
@@ -100,16 +100,6 @@ flag {
}
flag {
- name: "hfp_allow_volume_change_without_sco"
- namespace: "bluetooth"
- description: "Allow Audio Fwk to change SCO volume when HFP profile is connected and SCO not connected"
- bug: "362313390"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "choose_wrong_hfp_codec_in_specific_config"
namespace: "bluetooth"
description: "Flag to fix codec selection in nego when the peer device only support NB and SWB."
diff --git a/flags/le_scanning.aconfig b/flags/le_scanning.aconfig
new file mode 100644
index 0000000000..0b4985e45e
--- /dev/null
+++ b/flags/le_scanning.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.bluetooth.flags"
+container: "com.android.bt"
+
+flag {
+ name: "scan_results_in_main_thread"
+ namespace: "bluetooth"
+ description: "Use main thread for handling scan results"
+ bug: "392693506"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/leaudio.aconfig b/flags/leaudio.aconfig
index e7b0b2abcf..03cc9a4c02 100644
--- a/flags/leaudio.aconfig
+++ b/flags/leaudio.aconfig
@@ -451,3 +451,13 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "leaudio_disable_broadcast_for_hap_device"
+ namespace: "bluetooth"
+ description: "Disable broadcast feature for HAP device"
+ bug: "391702876"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/security.aconfig b/flags/security.aconfig
index ddfd78611c..006c51f307 100644
--- a/flags/security.aconfig
+++ b/flags/security.aconfig
@@ -9,6 +9,16 @@ flag {
}
flag {
+ name: "key_missing_ble_peripheral"
+ namespace: "bluetooth"
+ description: "Key missing broadcast for LE devices in peripheral role"
+ bug: "392895615"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "key_missing_as_ordered_broadcast"
namespace: "bluetooth"
description: "Key missing broadcast would be send as ordered broadcast"
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 5a506f21fb..60657262e3 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -53,7 +53,7 @@ package android.bluetooth {
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void disableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void enableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BufferConstraints getBufferConstraints();
- method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
+ method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}, conditional=true) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getDynamicBufferSupport();
method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice);
diff --git a/framework/java/android/bluetooth/BluetoothA2dp.java b/framework/java/android/bluetooth/BluetoothA2dp.java
index 5bcd0789ab..54f2c702aa 100644
--- a/framework/java/android/bluetooth/BluetoothA2dp.java
+++ b/framework/java/android/bluetooth/BluetoothA2dp.java
@@ -724,20 +724,23 @@ public final class BluetoothA2dp implements BluetoothProfile {
/**
* Gets the current codec status (configuration and capability).
*
+ * <p>This method requires the calling app to have the {@link
+ * android.Manifest.permission#BLUETOOTH_CONNECT} permission. Additionally, an app must either
+ * have the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} or be associated with the
+ * Companion Device manager (see {@link android.companion.CompanionDeviceManager#associate(
+ * AssociationRequest, android.companion.CompanionDeviceManager.Callback, Handler)})
+ *
* @param device the remote Bluetooth device.
* @return the current codec status
* @hide
*/
@SystemApi
- @Nullable
@RequiresLegacyBluetoothPermission
@RequiresBluetoothConnectPermission
@RequiresPermission(
- allOf = {
- BLUETOOTH_CONNECT,
- BLUETOOTH_PRIVILEGED,
- })
- public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
+ allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED},
+ conditional = true)
+ public @Nullable BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
verifyDeviceNotNull(device, "getCodecStatus");
final IBluetoothA2dp service = getService();
diff --git a/framework/java/android/bluetooth/BluetoothGatt.java b/framework/java/android/bluetooth/BluetoothGatt.java
index e67d823c7e..a69c8ba792 100644
--- a/framework/java/android/bluetooth/BluetoothGatt.java
+++ b/framework/java/android/bluetooth/BluetoothGatt.java
@@ -37,6 +37,8 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
+import com.android.bluetooth.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -243,6 +245,9 @@ public final class BluetoothGatt implements BluetoothProfile {
+ " unregistering");
}
unregisterApp();
+ if (Flags.unregisterGattClientDisconnected()) {
+ mCallback = null;
+ }
return;
}
if (VDBG) {
@@ -274,7 +279,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
// autoConnect is inverse of "isDirect"
mService.clientConnect(
- mClientIf,
+ clientIf,
mDevice.getAddress(),
mDevice.getAddressType(),
!mAutoConnect,
@@ -361,6 +366,8 @@ public final class BluetoothGatt implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresBluetoothConnectPermission
+ @RequiresPermission(BLUETOOTH_CONNECT)
public void onClientConnectionState(
int status, int clientIf, boolean connected, String address) {
if (DBG) {
@@ -381,6 +388,10 @@ public final class BluetoothGatt implements BluetoothProfile {
? BluetoothProfile.STATE_CONNECTED
: BluetoothProfile.STATE_DISCONNECTED;
+ if (Flags.unregisterGattClientDisconnected() && !connected && !mAutoConnect) {
+ unregisterApp();
+ }
+
runOrQueueCallback(
new Runnable() {
@Override
@@ -433,6 +444,10 @@ public final class BluetoothGatt implements BluetoothProfile {
s.setDevice(mDevice);
}
+ if (Flags.fixBluetoothGattGettingDuplicateServices()) {
+ mServices.clear();
+ }
+
mServices.addAll(services);
// Fix references to included services, as they doesn't point to right objects.
@@ -493,16 +508,18 @@ public final class BluetoothGatt implements BluetoothProfile {
mDeviceBusy = false;
}
+ int clientIf = mClientIf;
if ((status == GATT_INSUFFICIENT_AUTHENTICATION
|| status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
+ && (mAuthRetryState != AUTH_RETRY_STATE_MITM)
+ && (clientIf > 0)) {
try {
final int authReq =
(mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM
: AUTHENTICATION_MITM;
mService.readCharacteristic(
- mClientIf, address, handle, authReq, mAttributionSource);
+ clientIf, address, handle, authReq, mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -573,10 +590,13 @@ public final class BluetoothGatt implements BluetoothProfile {
? AUTHENTICATION_NO_MITM
: AUTHENTICATION_MITM;
int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
- for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
+ int clientIf = mClientIf;
+ for (int i = 0;
+ (i < WRITE_CHARACTERISTIC_MAX_RETRIES) && (clientIf > 0);
+ i++) {
requestStatus =
mService.writeCharacteristic(
- mClientIf,
+ clientIf,
address,
handle,
characteristic.getWriteType(),
@@ -679,16 +699,18 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
if (descriptor == null) return;
+ int clientIf = mClientIf;
if ((status == GATT_INSUFFICIENT_AUTHENTICATION
|| status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
+ && (mAuthRetryState != AUTH_RETRY_STATE_MITM)
+ && (clientIf > 0)) {
try {
final int authReq =
(mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM
: AUTHENTICATION_MITM;
mService.readDescriptor(
- mClientIf, address, handle, authReq, mAttributionSource);
+ clientIf, address, handle, authReq, mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -741,16 +763,18 @@ public final class BluetoothGatt implements BluetoothProfile {
BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
if (descriptor == null) return;
+ int clientIf = mClientIf;
if ((status == GATT_INSUFFICIENT_AUTHENTICATION
|| status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
+ && (mAuthRetryState != AUTH_RETRY_STATE_MITM)
+ && (clientIf > 0)) {
try {
final int authReq =
(mAuthRetryState == AUTH_RETRY_STATE_IDLE)
? AUTHENTICATION_NO_MITM
: AUTHENTICATION_MITM;
mService.writeDescriptor(
- mClientIf, address, handle, authReq, value, mAttributionSource);
+ clientIf, address, handle, authReq, value, mAttributionSource);
mAuthRetryState++;
return;
} catch (RemoteException e) {
@@ -1033,6 +1057,10 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "close()");
unregisterApp();
+ if (Flags.unregisterGattClientDisconnected()) {
+ mCallback = null;
+ }
+
mConnState = CONN_STATE_CLOSED;
mAuthRetryState = AUTH_RETRY_STATE_IDLE;
}
@@ -1166,7 +1194,9 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
try {
- mCallback = null;
+ if (!Flags.unregisterGattClientDisconnected()) {
+ mCallback = null;
+ }
mService.unregisterClient(mClientIf, mAttributionSource);
mClientIf = 0;
} catch (RemoteException e) {
@@ -1229,10 +1259,11 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public void disconnect() {
if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return;
try {
- mService.clientDisconnect(mClientIf, mDevice.getAddress(), mAttributionSource);
+ mService.clientDisconnect(clientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1250,6 +1281,40 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresBluetoothConnectPermission
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean connect() {
+ int clientIf = mClientIf;
+ if (mService == null) return false;
+ if (clientIf == 0) {
+ if (!Flags.unregisterGattClientDisconnected()) {
+ return false;
+ }
+ synchronized (mStateLock) {
+ if (mConnState != CONN_STATE_IDLE) {
+ return false;
+ }
+ mConnState = CONN_STATE_CONNECTING;
+ }
+
+ UUID uuid = UUID.randomUUID();
+ if (DBG) Log.d(TAG, "reconnect from connect(), UUID=" + uuid);
+
+ try {
+ mService.registerClient(
+ new ParcelUuid(uuid),
+ mBluetoothGattCallback,
+ /* eatt_support= */ false,
+ mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ synchronized (mStateLock) {
+ mConnState = CONN_STATE_IDLE;
+ }
+ Log.e(TAG, "Failed to register callback");
+ return false;
+ }
+
+ return true;
+ }
+
try {
if (DBG) {
Log.d(TAG, "connect(void) - device: " + mDevice + ", auto=" + mAutoConnect);
@@ -1257,7 +1322,7 @@ public final class BluetoothGatt implements BluetoothProfile {
// autoConnect is inverse of "isDirect"
mService.clientConnect(
- mClientIf,
+ clientIf,
mDevice.getAddress(),
mDevice.getAddressType(),
!mAutoConnect,
@@ -1293,9 +1358,12 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresBluetoothConnectPermission
@RequiresPermission(BLUETOOTH_CONNECT)
public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return;
+
try {
mService.clientSetPreferredPhy(
- mClientIf, mDevice.getAddress(), txPhy, rxPhy, phyOptions, mAttributionSource);
+ clientIf, mDevice.getAddress(), txPhy, rxPhy, phyOptions, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1308,8 +1376,11 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresBluetoothConnectPermission
@RequiresPermission(BLUETOOTH_CONNECT)
public void readPhy() {
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return;
+
try {
- mService.clientReadPhy(mClientIf, mDevice.getAddress(), mAttributionSource);
+ mService.clientReadPhy(clientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1340,12 +1411,16 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean discoverServices() {
if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return false;
- mServices.clear();
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
+
+ if (!Flags.fixBluetoothGattGettingDuplicateServices()) {
+ mServices.clear();
+ }
try {
- mService.discoverServices(mClientIf, mDevice.getAddress(), mAttributionSource);
+ mService.discoverServices(clientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1367,13 +1442,16 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean discoverServiceByUuid(UUID uuid) {
if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
- mServices.clear();
+ if (!Flags.fixBluetoothGattGettingDuplicateServices()) {
+ mServices.clear();
+ }
try {
mService.discoverServiceByUuid(
- mClientIf, mDevice.getAddress(), new ParcelUuid(uuid), mAttributionSource);
+ clientIf, mDevice.getAddress(), new ParcelUuid(uuid), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1447,7 +1525,8 @@ public final class BluetoothGatt implements BluetoothProfile {
}
if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid());
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
BluetoothGattService service = characteristic.getService();
if (service == null) return false;
@@ -1462,7 +1541,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
mService.readCharacteristic(
- mClientIf,
+ clientIf,
device.getAddress(),
characteristic.getInstanceId(),
AUTHENTICATION_NONE,
@@ -1494,7 +1573,8 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
@@ -1503,7 +1583,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
mService.readUsingCharacteristicUuid(
- mClientIf,
+ clientIf,
mDevice.getAddress(),
new ParcelUuid(uuid),
startHandle,
@@ -1601,7 +1681,8 @@ public final class BluetoothGatt implements BluetoothProfile {
== 0) {
return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED;
}
- if (mService == null || mClientIf == 0) {
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) {
return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
}
@@ -1627,7 +1708,7 @@ public final class BluetoothGatt implements BluetoothProfile {
for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
requestStatus =
mService.writeCharacteristic(
- mClientIf,
+ clientIf,
device.getAddress(),
characteristic.getInstanceId(),
writeType,
@@ -1674,7 +1755,8 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
if (characteristic == null) return false;
@@ -1692,7 +1774,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
mService.readDescriptor(
- mClientIf,
+ clientIf,
device.getAddress(),
descriptor.getInstanceId(),
AUTHENTICATION_NONE,
@@ -1755,7 +1837,8 @@ public final class BluetoothGatt implements BluetoothProfile {
throw new IllegalArgumentException("value must not be null");
}
if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
- if (mService == null || mClientIf == 0) {
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) {
return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
}
@@ -1781,7 +1864,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
return mService.writeDescriptor(
- mClientIf,
+ clientIf,
device.getAddress(),
descriptor.getInstanceId(),
AUTHENTICATION_NONE,
@@ -1818,10 +1901,11 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean beginReliableWrite() {
if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
try {
- mService.beginReliableWrite(mClientIf, mDevice.getAddress(), mAttributionSource);
+ mService.beginReliableWrite(clientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1846,7 +1930,8 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean executeReliableWrite() {
if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
synchronized (mDeviceBusyLock) {
if (mDeviceBusy) return false;
@@ -1854,7 +1939,7 @@ public final class BluetoothGatt implements BluetoothProfile {
}
try {
- mService.endReliableWrite(mClientIf, mDevice.getAddress(), true, mAttributionSource);
+ mService.endReliableWrite(clientIf, mDevice.getAddress(), true, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
synchronized (mDeviceBusyLock) {
@@ -1877,10 +1962,11 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public void abortReliableWrite() {
if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return;
try {
- mService.endReliableWrite(mClientIf, mDevice.getAddress(), false, mAttributionSource);
+ mService.endReliableWrite(clientIf, mDevice.getAddress(), false, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -1921,7 +2007,8 @@ public final class BluetoothGatt implements BluetoothProfile {
+ " enable: "
+ enable);
}
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
BluetoothGattService service = characteristic.getService();
if (service == null) return false;
@@ -1931,7 +2018,7 @@ public final class BluetoothGatt implements BluetoothProfile {
try {
mService.registerForNotification(
- mClientIf,
+ clientIf,
device.getAddress(),
characteristic.getInstanceId(),
enable,
@@ -1954,10 +2041,11 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean refresh() {
if (DBG) Log.d(TAG, "refresh() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
try {
- mService.refreshDevice(mClientIf, mDevice.getAddress(), mAttributionSource);
+ mService.refreshDevice(clientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -1979,10 +2067,11 @@ public final class BluetoothGatt implements BluetoothProfile {
@RequiresPermission(BLUETOOTH_CONNECT)
public boolean readRemoteRssi() {
if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
try {
- mService.readRemoteRssi(mClientIf, mDevice.getAddress(), mAttributionSource);
+ mService.readRemoteRssi(clientIf, mDevice.getAddress(), mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -2014,10 +2103,11 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) {
Log.d(TAG, "configureMTU() - device: " + mDevice + " mtu: " + mtu);
}
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
try {
- mService.configureMTU(mClientIf, mDevice.getAddress(), mtu, mAttributionSource);
+ mService.configureMTU(clientIf, mDevice.getAddress(), mtu, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -2047,11 +2137,12 @@ public final class BluetoothGatt implements BluetoothProfile {
}
if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority);
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
try {
mService.connectionParameterUpdate(
- mClientIf, mDevice.getAddress(), connectionPriority, mAttributionSource);
+ clientIf, mDevice.getAddress(), connectionPriority, mAttributionSource);
} catch (RemoteException e) {
Log.e(TAG, "", e);
return false;
@@ -2098,11 +2189,12 @@ public final class BluetoothGatt implements BluetoothProfile {
+ ", max_ce="
+ maxConnectionEventLen);
}
- if (mService == null || mClientIf == 0) return false;
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) return false;
try {
mService.leConnectionUpdate(
- mClientIf,
+ clientIf,
mDevice.getAddress(),
minConnectionInterval,
maxConnectionInterval,
@@ -2148,12 +2240,13 @@ public final class BluetoothGatt implements BluetoothProfile {
if (DBG) {
Log.d(TAG, "requestsubrateMode(" + subrateMode + ")");
}
- if (mService == null || mClientIf == 0) {
+ int clientIf = mClientIf;
+ if (mService == null || clientIf == 0) {
return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
}
try {
- return mService.subrateModeRequest(mClientIf, mDevice, subrateMode, mAttributionSource);
+ return mService.subrateModeRequest(clientIf, mDevice, subrateMode, mAttributionSource);
} catch (RemoteException e) {
logRemoteException(TAG, e);
return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
diff --git a/framework/java/android/bluetooth/BluetoothSocket.java b/framework/java/android/bluetooth/BluetoothSocket.java
index 97bdf595a0..cde23baf4d 100644
--- a/framework/java/android/bluetooth/BluetoothSocket.java
+++ b/framework/java/android/bluetooth/BluetoothSocket.java
@@ -978,6 +978,8 @@ public final class BluetoothSocket implements Closeable {
if (mL2capBuffer.remaining() == 0) {
if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
if (fillL2capRxBuffer() == -1) {
+ Log.d(TAG, "socket EOF, returning -1");
+ mSocketState = SocketState.CLOSED;
return -1;
}
}
@@ -994,6 +996,7 @@ public final class BluetoothSocket implements Closeable {
ret = mSocketIS.read(b, offset, length);
}
if (ret < 0) {
+ mSocketState = SocketState.CLOSED;
throw new IOException("bt socket closed, read return: " + ret);
}
if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret);
diff --git a/framework/tests/bumble/src/android/bluetooth/DckL2capTest.kt b/framework/tests/bumble/src/android/bluetooth/DckL2capTest.kt
index e658e8c645..ea41c55ee0 100644
--- a/framework/tests/bumble/src/android/bluetooth/DckL2capTest.kt
+++ b/framework/tests/bumble/src/android/bluetooth/DckL2capTest.kt
@@ -226,6 +226,51 @@ public class DckL2capTest() : Closeable {
Log.d(TAG, "testReceive: done")
}
+ @Test
+ @VirtualOnly
+ fun testReadReturnOnRemoteSocketDisconnect() {
+ Log.d(TAG, "testReadReturnonSocketDisconnect: Connect L2CAP")
+ var bluetoothSocket: BluetoothSocket?
+ val l2capServer = bluetoothAdapter.listenUsingInsecureL2capChannel()
+ val socketFlow = flow { emit(l2capServer.accept()) }
+ val connectResponse = createAndConnectL2capChannelWithBumble(l2capServer.psm)
+ runBlocking {
+ bluetoothSocket = socketFlow.first()
+ assertThat(connectResponse.hasChannel()).isTrue()
+ }
+
+ val inputStream = bluetoothSocket!!.inputStream
+
+ // block on read() on server thread
+ val readThread = Thread {
+ Log.d(TAG, "testReadReturnOnRemoteSocketDisconnect: Receive data on Android")
+ val ret = inputStream.read()
+ Log.d(TAG, "testReadReturnOnRemoteSocketDisconnect: read returns : " + ret)
+ Log.d(
+ TAG,
+ "testReadReturnOnRemoteSocketDisconnect: isConnected() : " +
+ bluetoothSocket!!.isConnected(),
+ )
+ assertThat(ret).isEqualTo(-1)
+ assertThat(bluetoothSocket!!.isConnected()).isFalse()
+ }
+ readThread.start()
+ // check that socket is still connected
+ assertThat(bluetoothSocket!!.isConnected()).isTrue()
+
+ // read() would be blocking till underlying l2cap is disconnected
+ Thread.sleep(1000 * 10)
+ Log.d(TAG, "testReadReturnOnRemoteSocketDisconnect: disconnect after 10 secs")
+ val disconnectRequest =
+ DisconnectRequest.newBuilder().setChannel(connectResponse.channel).build()
+ val disconnectResponse = mBumble.l2capBlocking().disconnect(disconnectRequest)
+ assertThat(disconnectResponse.hasSuccess()).isTrue()
+ inputStream.close()
+ bluetoothSocket?.close()
+ l2capServer.close()
+ Log.d(TAG, "testReadReturnOnRemoteSocketDisconnect: done")
+ }
+
private fun createAndConnectL2capChannelWithBumble(psm: Int): ConnectResponse {
Log.d(TAG, "createAndConnectL2capChannelWithBumble")
val remoteDevice =
diff --git a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java
index c9fa50bbd9..64ada411d6 100644
--- a/framework/tests/bumble/src/android/bluetooth/GattClientTest.java
+++ b/framework/tests/bumble/src/android/bluetooth/GattClientTest.java
@@ -720,6 +720,44 @@ public class GattClientTest {
}
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_UNREGISTER_GATT_CLIENT_DISCONNECTED)
+ public void connectAndDisconnectManyClientsWithoutClose() throws Exception {
+ advertiseWithBumble();
+
+ List<BluetoothGatt> gatts = new ArrayList<>();
+ try {
+ for (int i = 0; i < 100; i++) {
+ BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class);
+ InOrder inOrder = inOrder(gattCallback);
+
+ BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, false, gattCallback);
+ gatts.add(gatt);
+
+ inOrder.verify(gattCallback, timeout(1000))
+ .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED));
+
+ gatt.disconnect();
+ inOrder.verify(gattCallback, timeout(1000))
+ .onConnectionStateChange(
+ any(), anyInt(), eq(BluetoothProfile.STATE_DISCONNECTED));
+
+ gatt.connect();
+ inOrder.verify(gattCallback, timeout(1000))
+ .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED));
+
+ gatt.disconnect();
+ inOrder.verify(gattCallback, timeout(1000))
+ .onConnectionStateChange(
+ any(), anyInt(), eq(BluetoothProfile.STATE_DISCONNECTED));
+ }
+ } finally {
+ for (BluetoothGatt gatt : gatts) {
+ gatt.close();
+ }
+ }
+ }
+
private void createLeBondAndWaitBonding(BluetoothDevice device) {
advertiseWithBumble();
mHost.createBondAndVerify(device);
diff --git a/offload/hal/service.rs b/offload/hal/service.rs
index 779be6da8c..eb8c679b09 100644
--- a/offload/hal/service.rs
+++ b/offload/hal/service.rs
@@ -16,7 +16,7 @@ use crate::ffi::{CInterface, CStatus, Callbacks, DataCallbacks, Ffi};
use android_hardware_bluetooth::aidl::android::hardware::bluetooth::{
IBluetoothHci::IBluetoothHci, IBluetoothHciCallbacks::IBluetoothHciCallbacks, Status::Status,
};
-use binder::{DeathRecipient, ExceptionCode, Interface, Result as BinderResult, Strong};
+use binder::{DeathRecipient, ExceptionCode, IBinder, Interface, Result as BinderResult, Strong};
use bluetooth_offload_hci::{Module, ModuleBuilder};
use std::sync::{Arc, RwLock};
@@ -41,7 +41,6 @@ struct SinkModule<T: Callbacks> {
enum State {
Closed,
- Opening { ffi: Arc<Ffi<FfiCallbacks>>, proxy: Arc<dyn Module> },
Opened { proxy: Arc<dyn Module>, _death_recipient: DeathRecipient },
}
@@ -73,10 +72,25 @@ impl IBluetoothHci for HciHalProxy {
for m in self.modules.iter().rev() {
proxy = m.build(proxy);
}
- let callbacks = FfiCallbacks::new(callbacks.clone(), proxy.clone(), self.state.clone());
- *state = State::Opening { ffi: self.ffi.clone(), proxy: proxy.clone() };
- (self.ffi.clone(), callbacks)
+ let mut death_recipient = {
+ let (ffi, state) = (self.ffi.clone(), self.state.clone());
+ DeathRecipient::new(move || {
+ log::info!("Bluetooth stack has died");
+ let mut state = state.write().unwrap();
+ if !matches!(*state, State::Closed) {
+ ffi.close();
+ }
+ *state = State::Closed;
+ })
+ };
+ callbacks.as_binder().link_to_death(&mut death_recipient)?;
+
+ *state = State::Opened { proxy: proxy.clone(), _death_recipient: death_recipient };
+ (
+ self.ffi.clone(),
+ FfiCallbacks::new(callbacks.clone(), proxy.clone(), self.state.clone()),
+ )
};
ffi.initialize(callbacks);
@@ -185,31 +199,12 @@ impl FfiCallbacks {
impl Callbacks for FfiCallbacks {
fn initialization_complete(&self, status: CStatus) {
let mut state = self.state.write().unwrap();
- match status {
- CStatus::Success => {
- let State::Opening { ref ffi, ref proxy } = *state else {
- panic!("Initialization completed called in bad state");
- };
-
- *state = State::Opened {
- proxy: proxy.clone(),
- _death_recipient: {
- let (ffi, state) = (ffi.clone(), self.state.clone());
- DeathRecipient::new(move || {
- log::info!("Bluetooth stack has died");
- *state.write().unwrap() = State::Closed;
- ffi.close();
- })
- },
- };
- }
-
- CStatus::AlreadyInitialized => panic!("Initialization completed called in bad state"),
- _ => *state = State::Closed,
- };
-
+ if status != CStatus::Success {
+ *state = State::Closed;
+ }
if let Err(e) = self.callbacks.initializationComplete(status.into()) {
log::error!("Cannot call-back client: {:?}", e);
+ *state = State::Closed;
}
}
}
diff --git a/offload/hci/data.rs b/offload/hci/data.rs
index 0e20e82029..bb4a452a59 100644
--- a/offload/hci/data.rs
+++ b/offload/hci/data.rs
@@ -120,7 +120,7 @@ impl<'a> IsoData<'a> {
}
}
-impl<'a> Write for IsoData<'a> {
+impl Write for IsoData<'_> {
fn write(&self, w: &mut Writer) {
let (pb_flag, hdr) = match self.sdu_fragment {
IsoSduFragment::First { ref hdr, is_last: false } => (0b00, Some(hdr)),
diff --git a/offload/leaudio/hci/proxy.rs b/offload/leaudio/hci/proxy.rs
index 413a7f84b5..79e45f06e1 100644
--- a/offload/leaudio/hci/proxy.rs
+++ b/offload/leaudio/hci/proxy.rs
@@ -29,7 +29,6 @@ pub struct LeAudioModuleBuilder {}
pub(crate) struct LeAudioModule {
next_module: Arc<dyn Module>,
state: Mutex<State>,
- service: Service,
}
#[derive(Default)]
@@ -145,13 +144,14 @@ impl Stream {
impl ModuleBuilder for LeAudioModuleBuilder {
/// Build the HCI-Proxy module from the next module in the chain
fn build(&self, next_module: Arc<dyn Module>) -> Arc<dyn Module> {
+ Service::register();
Arc::new(LeAudioModule::new(next_module))
}
}
impl LeAudioModule {
pub(crate) fn new(next_module: Arc<dyn Module>) -> Self {
- Self { next_module, state: Mutex::new(Default::default()), service: Service::new() }
+ Self { next_module, state: Mutex::new(Default::default()) }
}
#[cfg(test)]
@@ -216,7 +216,7 @@ impl Module for LeAudioModule {
ret.iso_data_packet_length.into(),
ret.total_num_iso_data_packets.into(),
)));
- self.service.reset(Arc::downgrade(state.arbiter.as_ref().unwrap()));
+ Service::reset(Arc::downgrade(state.arbiter.as_ref().unwrap()));
}
ReturnParameters::LeSetCigParameters(ref ret) if ret.status == Status::Success => {
@@ -249,7 +249,7 @@ impl Module for LeAudioModule {
IsoType::Bis { ref c_to_p } => c_to_p,
};
- self.service.start_stream(
+ Service::start_stream(
ret.connection_handle,
StreamConfiguration {
isoIntervalUs: stream.iso_interval_us as i32,
@@ -265,7 +265,7 @@ impl Module for LeAudioModule {
let mut state = self.state.lock().unwrap();
let stream = state.stream.get_mut(&ret.connection_handle).unwrap();
if stream.state == StreamState::Enabled {
- self.service.stop_stream(ret.connection_handle);
+ Service::stop_stream(ret.connection_handle);
}
stream.state = StreamState::Disabled;
}
diff --git a/offload/leaudio/hci/service.rs b/offload/leaudio/hci/service.rs
index 85fac7168c..05bc377287 100644
--- a/offload/leaudio/hci/service.rs
+++ b/offload/leaudio/hci/service.rs
@@ -19,12 +19,10 @@ use aidl::android::hardware::bluetooth::offload::leaudio::{
IHciProxy::{BnHciProxy, BpHciProxy, IHciProxy},
IHciProxyCallbacks::IHciProxyCallbacks,
};
-use binder::{
- BinderFeatures, DeathRecipient, ExceptionCode, Interface, Result as BinderResult, Strong,
-};
+use binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong};
use bluetooth_offload_hci::IsoData;
use std::collections::HashMap;
-use std::sync::{Arc, Mutex, Weak};
+use std::sync::{Arc, LazyLock, Mutex, Weak};
pub(crate) use aidl::android::hardware::bluetooth::offload::leaudio::StreamConfiguration::StreamConfiguration;
@@ -32,27 +30,31 @@ pub(crate) struct Service {
state: Arc<Mutex<State>>,
}
+static SERVICE: LazyLock<Service> = LazyLock::new(|| {
+ let state = Arc::new(Mutex::new(State::default()));
+ HciProxy::register(state.clone());
+ Service { state }
+});
+
#[derive(Default)]
struct State {
arbiter: Weak<Arbiter>,
- callbacks: Option<Strong<dyn IHciProxyCallbacks>>,
streams: HashMap<u16, StreamConfiguration>,
+ callbacks: Option<Strong<dyn IHciProxyCallbacks>>,
}
impl Service {
- pub(crate) fn new() -> Self {
- let state = Arc::new(Mutex::new(State::default()));
- HciProxy::register(state.clone());
- Self { state }
+ pub(crate) fn register() {
+ LazyLock::force(&SERVICE);
}
- pub(crate) fn reset(&self, arbiter: Weak<Arbiter>) {
- let mut state = self.state.lock().unwrap();
+ pub(crate) fn reset(arbiter: Weak<Arbiter>) {
+ let mut state = SERVICE.state.lock().unwrap();
*state = State { arbiter, ..Default::default() }
}
- pub(crate) fn start_stream(&self, handle: u16, config: StreamConfiguration) {
- let mut state = self.state.lock().unwrap();
+ pub(crate) fn start_stream(handle: u16, config: StreamConfiguration) {
+ let mut state = SERVICE.state.lock().unwrap();
if let Some(callbacks) = &state.callbacks {
let _ = callbacks.startStream(handle.into(), &config);
} else {
@@ -61,8 +63,8 @@ impl Service {
state.streams.insert(handle, config);
}
- pub(crate) fn stop_stream(&self, handle: u16) {
- let mut state = self.state.lock().unwrap();
+ pub(crate) fn stop_stream(handle: u16) {
+ let mut state = SERVICE.state.lock().unwrap();
state.streams.remove(&handle);
if let Some(callbacks) = &state.callbacks {
let _ = callbacks.stopStream(handle.into());
@@ -72,28 +74,15 @@ impl Service {
struct HciProxy {
state: Arc<Mutex<State>>,
- _death_recipient: DeathRecipient,
}
impl Interface for HciProxy {}
impl HciProxy {
fn register(state: Arc<Mutex<State>>) {
- let death_recipient = {
- let state = state.clone();
- DeathRecipient::new(move || {
- log::info!("Client has died");
- state.lock().unwrap().callbacks = None;
- })
- };
-
binder::add_service(
&format!("{}/default", BpHciProxy::get_descriptor()),
- BnHciProxy::new_binder(
- Self { state, _death_recipient: death_recipient },
- BinderFeatures::default(),
- )
- .as_binder(),
+ BnHciProxy::new_binder(Self { state }, BinderFeatures::default()).as_binder(),
)
.expect("Failed to register service");
}
@@ -106,7 +95,6 @@ impl IHciProxy for HciProxy {
for (handle, config) in &state.streams {
let _ = callbacks.startStream((*handle).into(), config);
}
-
Ok(())
}
diff --git a/pandora/interfaces/pandora_experimental/mediaplayer.proto b/pandora/interfaces/pandora_experimental/mediaplayer.proto
index 98ac7b674d..69ead553d8 100644
--- a/pandora/interfaces/pandora_experimental/mediaplayer.proto
+++ b/pandora/interfaces/pandora_experimental/mediaplayer.proto
@@ -9,6 +9,7 @@ import "google/protobuf/empty.proto";
service MediaPlayer {
rpc Play(google.protobuf.Empty) returns (google.protobuf.Empty);
+ rpc PlayUpdated(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc Stop(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc Pause(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc Rewind(google.protobuf.Empty) returns (google.protobuf.Empty);
@@ -17,6 +18,7 @@ service MediaPlayer {
rpc Backward(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc SetLargeMetadata(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc UpdateQueue(google.protobuf.Empty) returns (google.protobuf.Empty);
+ rpc ResetQueue(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc GetShuffleMode(google.protobuf.Empty) returns (GetShuffleModeResponse);
rpc SetShuffleMode(SetShuffleModeRequest) returns (google.protobuf.Empty);
rpc StartTestPlayback(google.protobuf.Empty) returns (google.protobuf.Empty);
diff --git a/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc b/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc
index ccd0bf04fe..8ab27d06d2 100644
--- a/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc
+++ b/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info.cc
@@ -171,9 +171,6 @@ static std::optional<btav_a2dp_codec_index_t> assignSinkCodecIndex(
int codec_id = codec.id.get<CodecId::vendor>().codecId;
/* match know vendor codecs */
- if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
- return BTAV_A2DP_CODEC_INDEX_SINK_LDAC;
- }
if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
return BTAV_A2DP_CODEC_INDEX_SINK_OPUS;
}
diff --git a/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info_unittest.cc b/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info_unittest.cc
index b3731e5627..6ac1bee5ed 100644
--- a/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info_unittest.cc
+++ b/system/audio_hal_interface/aidl/a2dp/a2dp_provider_info_unittest.cc
@@ -269,7 +269,7 @@ TEST_F(ProviderInfoTest, TestGetCodecNotSupported) {
GetProviderInfoForTesting(true, false);
auto received_codec_info_not_supported_codec =
- provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SINK_LDAC);
+ provider_info->GetCodec(BTAV_A2DP_CODEC_INDEX_SINK_MAX);
ASSERT_FALSE(received_codec_info_not_supported_codec.has_value());
}
diff --git a/system/audio_hal_interface/aidl/a2dp/codec_status_aidl.cc b/system/audio_hal_interface/aidl/a2dp/codec_status_aidl.cc
index cb4a601f0a..dfdebd2071 100644
--- a/system/audio_hal_interface/aidl/a2dp/codec_status_aidl.cc
+++ b/system/audio_hal_interface/aidl/a2dp/codec_status_aidl.cc
@@ -502,16 +502,11 @@ bool UpdateOffloadingCapabilities(
codec_type_set.insert(CodecType::OPUS);
break;
case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
- [[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
- [[fallthrough]];
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- [[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
log::warn("Ignore sink codec_type={}", preference.codec_type);
break;
case BTAV_A2DP_CODEC_INDEX_MAX:
- [[fallthrough]];
default:
log::error("Unknown codec_type={}", preference.codec_type);
return false;
diff --git a/system/audio_hal_interface/fuzzer/README.md b/system/audio_hal_interface/fuzzer/README.md
index 6d92d8f81f..a54c5cb9d7 100644
--- a/system/audio_hal_interface/fuzzer/README.md
+++ b/system/audio_hal_interface/fuzzer/README.md
@@ -34,7 +34,7 @@ Fuzzers assigns values to the following parameters to pass on to libbt-audio-hal
|------------- |-------------| ----- |
| `status` | 0.`UNKNOWN` 1.`SUCCESS` 2.`UNSUPPORTED_CODEC_CONFIGURATION`
3.`FAILURE` 4.`PENDING` | Value obtained from FuzzedDataProvider |
-| `index` | 0.`BTAV_A2DP_CODEC_INDEX_SOURCE_SBC` 1.`BTAV_A2DP_CODEC_INDEX_SOURCE_AAC` 2.`BTAV_A2DP_CODEC_INDEX_SOURCE_APTX` 3.`BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD` 4.`BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC` 5.`BTAV_A2DP_CODEC_INDEX_SINK_SBC` 6.`BTAV_A2DP_CODEC_INDEX_SINK_AAC` 7.`BTAV_A2DP_CODEC_INDEX_SINK_LDAC` | Value obtained from FuzzedDataProvider |
+| `index` | 0.`BTAV_A2DP_CODEC_INDEX_SOURCE_SBC` 1.`BTAV_A2DP_CODEC_INDEX_SOURCE_AAC` 2.`BTAV_A2DP_CODEC_INDEX_SOURCE_APTX` 3.`BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD` 4.`BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC` 5.`BTAV_A2DP_CODEC_INDEX_SINK_SBC` 6.`BTAV_A2DP_CODEC_INDEX_SINK_AAC` | Value obtained from FuzzedDataProvider |
| `sessionType` | 0.`SessionType::UNKNOWN` 1.`SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH` 2.`SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH` 3.`SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH` | Value obtained from FuzzedDataProvider |
| `sessionType_2_1` | 0.`SessionType_2_1::UNKNOWN` 1.`SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH` 2.`SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH` 3.`SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH` 4.`SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH` 5.`SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH` 6.`SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH` 7.`SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH` | Value obtained from FuzzedDataProvider |
| `param.sampleRate` | 0.`SampleRate::RATE_UNKNOWN` 1.`SampleRate::RATE_8000` 2.`SampleRate::RATE_16000` 3.`SampleRate::RATE_24000` 4.`SampleRate::RATE_32000` 5.`SampleRate::RATE_44100` 6.`SampleRate::RATE_48000` | Value obtained from FuzzedDataProvider |
diff --git a/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp b/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp
index 7613b7efe6..64a85ddfe4 100644
--- a/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp
+++ b/system/audio_hal_interface/fuzzer/libbt_audio_hal_a2dp_encoding_fuzzer.cpp
@@ -42,7 +42,7 @@ constexpr btav_a2dp_codec_index_t kCodecIndices[] = {
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, BTAV_A2DP_CODEC_INDEX_SINK_SBC,
- BTAV_A2DP_CODEC_INDEX_SINK_AAC, BTAV_A2DP_CODEC_INDEX_SINK_LDAC};
+ BTAV_A2DP_CODEC_INDEX_SINK_AAC};
std::vector<std::vector<btav_a2dp_codec_config_t>> CodecOffloadingPreferenceGenerator() {
std::vector<std::vector<btav_a2dp_codec_config_t>> offloadingPreferences = {
diff --git a/system/audio_hal_interface/fuzzer/libbt_audio_hal_client_interface_fuzzer.cpp b/system/audio_hal_interface/fuzzer/libbt_audio_hal_client_interface_fuzzer.cpp
index c309d44b34..7f5bbfc0c6 100644
--- a/system/audio_hal_interface/fuzzer/libbt_audio_hal_client_interface_fuzzer.cpp
+++ b/system/audio_hal_interface/fuzzer/libbt_audio_hal_client_interface_fuzzer.cpp
@@ -131,7 +131,7 @@ constexpr btav_a2dp_codec_index_t kCodecIndices[] = {
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, BTAV_A2DP_CODEC_INDEX_SINK_SBC,
- BTAV_A2DP_CODEC_INDEX_SINK_AAC, BTAV_A2DP_CODEC_INDEX_SINK_LDAC};
+ BTAV_A2DP_CODEC_INDEX_SINK_AAC};
class TestSinkTransport : public bluetooth::audio::hidl::IBluetoothSinkTransportInstance {
private:
diff --git a/system/audio_hal_interface/hidl/client_interface_hidl_unittest.cc b/system/audio_hal_interface/hidl/client_interface_hidl_unittest.cc
index 13ed21c06f..b9ac810b17 100644
--- a/system/audio_hal_interface/hidl/client_interface_hidl_unittest.cc
+++ b/system/audio_hal_interface/hidl/client_interface_hidl_unittest.cc
@@ -126,7 +126,7 @@ constexpr btav_a2dp_codec_index_t codec_indexes[] = {
BTAV_A2DP_CODEC_INDEX_SOURCE_SBC, BTAV_A2DP_CODEC_INDEX_SOURCE_AAC,
BTAV_A2DP_CODEC_INDEX_SOURCE_APTX, BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD,
BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, BTAV_A2DP_CODEC_INDEX_SINK_SBC,
- BTAV_A2DP_CODEC_INDEX_SINK_AAC, BTAV_A2DP_CODEC_INDEX_SINK_LDAC};
+ BTAV_A2DP_CODEC_INDEX_SINK_AAC};
constexpr uint16_t kPeerMtus[5] = {660, 663, 883, 1005, 1500};
class TestSinkTransport : public bluetooth::audio::hidl::IBluetoothSinkTransportInstance {
diff --git a/system/audio_hal_interface/hidl/codec_status_hidl.cc b/system/audio_hal_interface/hidl/codec_status_hidl.cc
index fe54dbdb1e..a74592a60c 100644
--- a/system/audio_hal_interface/hidl/codec_status_hidl.cc
+++ b/system/audio_hal_interface/hidl/codec_status_hidl.cc
@@ -463,16 +463,11 @@ bool UpdateOffloadingCapabilities(
log::warn("Ignore source codec_type={}, not supported on HIDL", preference.codec_type);
break;
case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
- [[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
- [[fallthrough]];
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- [[fallthrough]];
case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
log::warn("Ignore sink codec_type={}", preference.codec_type);
break;
case BTAV_A2DP_CODEC_INDEX_MAX:
- [[fallthrough]];
default:
log::error("Unknown codec_type={}", preference.codec_type);
return false;
diff --git a/system/bta/av/bta_av_aact.cc b/system/bta/av/bta_av_aact.cc
index 5854c8aa6c..769cefc4d9 100644
--- a/system/bta/av/bta_av_aact.cc
+++ b/system/bta/av/bta_av_aact.cc
@@ -878,17 +878,6 @@ void bta_av_cleanup(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* /* p_data */) {
alarm_cancel(p_scb->accept_open_timer);
}
- /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
- vendor_get_interface()->send_command(
- (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_STOP, (void*)&p_scb->l2c_cid);
- if (p_scb->offload_start_pending) {
- tBTA_AV_STATUS status = BTA_AV_FAIL_STREAM;
- tBTA_AV bta_av_data;
- bta_av_data.status = status;
- (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
- }
- */
-
if (p_scb->deregistering) {
/* remove stream */
for (int i = 0; i < BTAV_A2DP_CODEC_INDEX_MAX; i++) {
@@ -3185,67 +3174,32 @@ void bta_av_vendor_offload_stop() {
*
******************************************************************************/
void bta_av_offload_req(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* /*p_data*/) {
- tBTA_AV_STATUS status = BTA_AV_FAIL_RESOURCES;
-
+ tBTA_AV bta_av_data = {};
tBT_A2DP_OFFLOAD offload_start;
log::verbose("stream {}, audio channels open {}", p_scb->started ? "STARTED" : "STOPPED",
bta_av_cb.audio_open_cnt);
- A2dpCodecConfig* codec_config = bta_av_get_a2dp_current_codec();
- log::assert_that(codec_config != nullptr, "assert failed: codec_config != nullptr");
+ if (!p_scb->started) {
+ log::warn("stream not started, start offload failed.");
+ bta_av_data.status = BTA_AV_FAIL_STREAM;
+ (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
+ return;
+ }
- /* Check if stream has already been started. */
- /* Support offload if only one audio source stream is open. */
- if (p_scb->started != true) {
- status = BTA_AV_FAIL_STREAM;
- } else if (bta_av_cb.offload_start_pending_hndl || bta_av_cb.offload_started_hndl) {
+ if (bta_av_cb.offload_start_pending_hndl || bta_av_cb.offload_started_hndl) {
log::warn("offload already started, ignore request");
return;
- } else if (::bluetooth::audio::a2dp::provider::supports_codec(codec_config->codecIndex())) {
+ }
+
+ A2dpCodecConfig* codec_config = bta_av_get_a2dp_current_codec();
+ log::assert_that(codec_config != nullptr, "assert failed: codec_config != nullptr");
+
+ if (::bluetooth::audio::a2dp::provider::supports_codec(codec_config->codecIndex())) {
bta_av_vendor_offload_start_v2(p_scb, static_cast<A2dpCodecConfigExt*>(codec_config));
} else {
bta_av_offload_codec_builder(p_scb, &offload_start);
bta_av_vendor_offload_start(p_scb, &offload_start);
- return;
- }
- if (status != BTA_AV_SUCCESS) {
- tBTA_AV bta_av_data;
- bta_av_data.status = status;
- (*bta_av_cb.p_cback)(BTA_AV_OFFLOAD_START_RSP_EVT, &bta_av_data);
- }
- /* TODO(eisenbach): RE-IMPLEMENT USING VSC OR HAL EXTENSION
- else if (bta_av_cb.audio_open_cnt == 1 &&
- p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC &&
- p_scb->chnl == BTA_AV_CHNL_AUDIO) {
- bt_vendor_op_a2dp_offload_t a2dp_offload_start;
-
- if (L2CA_GetConnectionConfig(
- p_scb->l2c_cid, &a2dp_offload_start.acl_data_size,
- &a2dp_offload_start.remote_cid, &a2dp_offload_start.lm_handle)) {
- log::verbose("l2cmtu {} lcid 0x{:02X} rcid 0x{:02X} lm_handle 0x{:02X}",
- a2dp_offload_start.acl_data_size, p_scb->l2c_cid,
- a2dp_offload_start.remote_cid, a2dp_offload_start.lm_handle);
-
- a2dp_offload_start.bta_av_handle = p_scb->hndl;
- a2dp_offload_start.xmit_quota = BTA_AV_A2DP_OFFLOAD_XMIT_QUOTA;
- a2dp_offload_start.stream_mtu = p_scb->stream_mtu;
- a2dp_offload_start.local_cid = p_scb->l2c_cid;
- a2dp_offload_start.is_flushable = true;
- a2dp_offload_start.stream_source =
- ((uint32_t)(p_scb->cfg.codec_info[1] | p_scb->cfg.codec_info[2]));
-
- memcpy(a2dp_offload_start.codec_info, p_scb->cfg.codec_info,
- sizeof(a2dp_offload_start.codec_info));
-
- if (!vendor_get_interface()->send_command(
- (vendor_opcode_t)BT_VND_OP_A2DP_OFFLOAD_START,
- &a2dp_offload_start)) {
- status = BTA_AV_SUCCESS;
- p_scb->offload_start_pending = true;
- }
- }
}
- */
}
/*******************************************************************************
diff --git a/system/bta/dm/bta_dm_disc.cc b/system/bta/dm/bta_dm_disc.cc
index e9c6ba5e77..c3977454f5 100644
--- a/system/bta/dm/bta_dm_disc.cc
+++ b/system/bta/dm/bta_dm_disc.cc
@@ -511,7 +511,7 @@ static void bta_dm_gatt_disc_complete(tCONN_ID conn_id, tGATT_STATUS status) {
log::verbose("conn_id = {}, status = {}, sdp_pending = {}, le_pending = {}", conn_id, status,
sdp_pending, le_pending);
- if (com::android::bluetooth::flags::bta_dm_discover_both() && sdp_pending && !le_pending) {
+ if (sdp_pending && !le_pending) {
/* LE Service discovery finished, and services were reported, but SDP is not
* finished yet. gatt_close_timer closed the connection, and we received
* this callback because of disconnection */
@@ -784,8 +784,7 @@ static void bta_dm_disc_sm_execute(tBTA_DM_DISC_EVT event, std::unique_ptr<tBTA_
"bad message type: {}", msg->index());
auto req = std::get<tBTA_DM_API_DISCOVER>(*msg);
- if (com::android::bluetooth::flags::bta_dm_discover_both() &&
- is_same_device(req.bd_addr, bta_dm_discovery_cb.peer_bdaddr)) {
+ if (is_same_device(req.bd_addr, bta_dm_discovery_cb.peer_bdaddr)) {
bta_dm_discover_services(std::get<tBTA_DM_API_DISCOVER>(*msg));
} else {
bta_dm_queue_disc(std::get<tBTA_DM_API_DISCOVER>(*msg));
diff --git a/system/bta/hh/bta_hh_headtracker.cc b/system/bta/hh/bta_hh_headtracker.cc
index c8b3e20f05..0282cb59d0 100644
--- a/system/bta/hh/bta_hh_headtracker.cc
+++ b/system/bta/hh/bta_hh_headtracker.cc
@@ -140,7 +140,10 @@ void bta_hh_headtracker_parse_service(tBTA_HH_DEV_CB* p_dev_cb, const gatt::Serv
bool bta_hh_headtracker_supported(tBTA_HH_DEV_CB* p_dev_cb) {
if (p_dev_cb->hid_srvc.headtracker_support == BTA_HH_UNKNOWN) {
bluetooth::Uuid remote_uuids[BT_MAX_NUM_UUIDS] = {};
- bt_property_t remote_properties = {BT_PROPERTY_UUIDS, sizeof(remote_uuids), &remote_uuids};
+ bt_property_t remote_properties = {com::android::bluetooth::flags::separate_service_storage()
+ ? BT_PROPERTY_UUIDS_LE
+ : BT_PROPERTY_UUIDS,
+ sizeof(remote_uuids), &remote_uuids};
const RawAddress& bd_addr = p_dev_cb->link_spec.addrt.bda;
p_dev_cb->hid_srvc.headtracker_support = BTA_HH_UNAVAILABLE;
diff --git a/system/bta/le_audio/client.cc b/system/bta/le_audio/client.cc
index 6dbb4ace85..03d3bc9652 100644
--- a/system/bta/le_audio/client.cc
+++ b/system/bta/le_audio/client.cc
@@ -1558,7 +1558,7 @@ public:
active_group_id_ = bluetooth::groups::kGroupUnknown;
}
- void ConfigureStream(LeAudioDeviceGroup* group, bool up_to_qos_configured) {
+ bool ConfigureStream(LeAudioDeviceGroup* group, bool up_to_qos_configured) {
log::debug("group_id: {}", group->group_id_);
BidirectionalPair<std::vector<uint8_t>> ccids = {
@@ -1566,11 +1566,16 @@ public:
local_metadata_context_types_.sink),
.source = ContentControlIdKeeper::GetInstance()->GetAllCcids(
local_metadata_context_types_.source)};
+
+ group->SetPendingConfiguration();
if (!groupStateMachine_->ConfigureStream(group, configuration_context_type_,
local_metadata_context_types_, ccids,
up_to_qos_configured)) {
- log::info("Could not configure group {}", group->group_id_);
+ group->ClearPendingConfiguration();
+ return false;
}
+
+ return true;
}
void PrepareStreamForAConversational(LeAudioDeviceGroup* group) {
@@ -1590,13 +1595,7 @@ public:
return;
}
- BidirectionalPair<std::vector<uint8_t>> ccids = {
- .sink = ContentControlIdKeeper::GetInstance()->GetAllCcids(
- local_metadata_context_types_.sink),
- .source = ContentControlIdKeeper::GetInstance()->GetAllCcids(
- local_metadata_context_types_.source)};
- if (!groupStateMachine_->ConfigureStream(group, configuration_context_type_,
- local_metadata_context_types_, ccids, true)) {
+ if (!ConfigureStream(group, true)) {
log::info("Reconfiguration is needed for group {}", group->group_id_);
initReconfiguration(group, LeAudioContextType::UNSPECIFIED);
}
@@ -1724,7 +1723,10 @@ public:
* only Enable will left.
* Otherwise, if there is group switch, let's move ASEs to Configured state.
*/
- ConfigureStream(group, prepare_for_a_call);
+
+ if (!ConfigureStream(group, prepare_for_a_call)) {
+ log::info("Could not configure group {}", group->group_id_);
+ }
}
/* Reset sink and source listener notified status */
@@ -6194,15 +6196,17 @@ public:
return;
}
- if (is_active_group_operation) {
- if (audio_sender_state_ != AudioState::IDLE) {
- audio_sender_state_ = AudioState::RELEASING;
- }
+ /* Releasing state shall be always set here, because we do support only single group
+ * streaming at the time. */
+ if (audio_sender_state_ != AudioState::IDLE) {
+ audio_sender_state_ = AudioState::RELEASING;
+ }
- if (audio_receiver_state_ != AudioState::IDLE) {
- audio_receiver_state_ = AudioState::RELEASING;
- }
+ if (audio_receiver_state_ != AudioState::IDLE) {
+ audio_receiver_state_ = AudioState::RELEASING;
+ }
+ if (is_active_group_operation) {
if (group && group->IsPendingConfiguration()) {
log::info("Releasing for reconfiguration, don't send anything on CISes");
SuspendedForReconfiguration();
diff --git a/system/bta/le_audio/le_audio_client_test.cc b/system/bta/le_audio/le_audio_client_test.cc
index 693494f73c..98ed3d3c2e 100644
--- a/system/bta/le_audio/le_audio_client_test.cc
+++ b/system/bta/le_audio/le_audio_client_test.cc
@@ -931,14 +931,16 @@ protected:
// Inject the state
group->SetTargetState(config_state);
group->SetState(group->GetTargetState());
- group->ClearPendingConfiguration();
- do_in_main_thread(base::BindOnce(
- [](int group_id, bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks*
- state_machine_callbacks) {
- state_machine_callbacks->StatusReportCb(
- group_id, GroupStreamStatus::CONFIGURED_BY_USER);
- },
- group->group_id_, base::Unretained(this->state_machine_callbacks_)));
+ if (group->IsPendingConfiguration()) {
+ group->ClearPendingConfiguration();
+ do_in_main_thread(base::BindOnce(
+ [](int group_id, bluetooth::le_audio::LeAudioGroupStateMachine::Callbacks*
+ state_machine_callbacks) {
+ state_machine_callbacks->StatusReportCb(
+ group_id, GroupStreamStatus::CONFIGURED_BY_USER);
+ },
+ group->group_id_, base::Unretained(this->state_machine_callbacks_)));
+ }
return true;
});
@@ -5081,6 +5083,9 @@ TEST_F(UnicastTest, AnotherGroupSetActive_DuringMediaStream) {
SyncOnMainLoop();
Mock::VerifyAndClearExpectations(&mock_state_machine_);
+
+ LocalAudioSourceResume();
+ SyncOnMainLoop();
}
TEST_F(UnicastTest, AnotherGroupSetActive_DuringVoip) {
diff --git a/system/bta/le_audio/state_machine.cc b/system/bta/le_audio/state_machine.cc
index 8d8ca50ab0..b4363d8253 100644
--- a/system/bta/le_audio/state_machine.cc
+++ b/system/bta/le_audio/state_machine.cc
@@ -1084,7 +1084,7 @@ public:
/* Note, that this type is actually LONG WRITE.
* Meaning all the Prepare Writes plus Execute is handled in the stack
*/
- write_type = GATT_WRITE_PREPARE;
+ write_type = GATT_WRITE;
}
BtaGattQueue::WriteCharacteristic(leAudioDevice->conn_id_, leAudioDevice->ctp_hdls_.val_hdl,
@@ -2293,6 +2293,7 @@ private:
if (group->GetTargetState() == AseState::BTA_LE_AUDIO_ASE_STATE_QOS_CONFIGURED) {
cancel_watchdog_if_needed(group->group_id_);
+ group->ClearPendingConfiguration();
state_machine_callbacks_->StatusReportCb(group->group_id_,
GroupStreamStatus::CONFIGURED_BY_USER);
return;
diff --git a/system/bta/test/bta_disc_test.cc b/system/bta/test/bta_disc_test.cc
index 58421f2962..3a1dbc9882 100644
--- a/system/bta/test/bta_disc_test.cc
+++ b/system/bta/test/bta_disc_test.cc
@@ -219,61 +219,7 @@ int gatt_service_cb_both_call_cnt = 0;
/* This test exercises the usual service discovery flow when bonding to
* dual-mode, CTKD capable device on LE transport.
*/
-TEST_F_WITH_FLAGS(BtaInitializedTest, bta_dm_disc_both_transports_flag_disabled,
- REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(TEST_BT, bta_dm_discover_both))) {
- bta_dm_disc_start(true);
-
- std::promise<void> gatt_triggered;
- int gatt_call_cnt = 0;
- base::RepeatingCallback<void(const RawAddress&)> gatt_performer =
- base::BindLambdaForTesting([&](const RawAddress& /*bd_addr*/) {
- gatt_call_cnt++;
- gatt_triggered.set_value();
- });
- bta_dm_disc_override_gatt_performer_for_testing(gatt_performer);
-
- int sdp_call_cnt = 0;
- base::RepeatingCallback<void(tBTA_DM_SDP_STATE*)> sdp_performer =
- base::BindLambdaForTesting([&](tBTA_DM_SDP_STATE* /*sdp_state*/) { sdp_call_cnt++; });
- bta_dm_disc_override_sdp_performer_for_testing(sdp_performer);
-
- gatt_service_cb_both_call_cnt = 0;
- service_cb_both_call_cnt = 0;
-
- bta_dm_disc_start_service_discovery(
- {[](RawAddress, std::vector<bluetooth::Uuid>&, bool) {}, nullptr,
- [](RawAddress /*addr*/, const std::vector<bluetooth::Uuid>&, tBTA_STATUS) {
- service_cb_both_call_cnt++;
- }},
- kRawAddress, BT_TRANSPORT_BR_EDR);
- EXPECT_EQ(sdp_call_cnt, 1);
-
- bta_dm_disc_start_service_discovery(
- {[](RawAddress, std::vector<bluetooth::Uuid>&, bool) { gatt_service_cb_both_call_cnt++; },
- nullptr, [](RawAddress /*addr*/, const std::vector<bluetooth::Uuid>&, tBTA_STATUS) {}},
- kRawAddress, BT_TRANSPORT_LE);
-
- // GATT discovery is queued, until SDP finishes
- EXPECT_EQ(gatt_call_cnt, 0);
-
- bta_dm_sdp_finished(kRawAddress, BTA_SUCCESS, {}, {});
- EXPECT_EQ(service_cb_both_call_cnt, 1);
-
- // SDP finished, wait until GATT is triggered.
- EXPECT_EQ(std::future_status::ready,
- gatt_triggered.get_future().wait_for(std::chrono::seconds(1)));
- bta_dm_gatt_finished(kRawAddress, BTA_SUCCESS);
- EXPECT_EQ(gatt_service_cb_both_call_cnt, 1);
-
- bta_dm_disc_override_sdp_performer_for_testing({});
- bta_dm_disc_override_gatt_performer_for_testing({});
-}
-
-/* This test exercises the usual service discovery flow when bonding to
- * dual-mode, CTKD capable device on LE transport.
- */
-TEST_F_WITH_FLAGS(BtaInitializedTest, bta_dm_disc_both_transports_flag_enabled,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_BT, bta_dm_discover_both))) {
+TEST_F(BtaInitializedTest, bta_dm_disc_both_transports) {
bta_dm_disc_start(true);
int gatt_call_cnt = 0;
diff --git a/system/btif/include/btif_dm.h b/system/btif/include/btif_dm.h
index b165baa441..9069c97b76 100644
--- a/system/btif/include/btif_dm.h
+++ b/system/btif/include/btif_dm.h
@@ -151,6 +151,7 @@ void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask, Octet16*
tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
void btif_update_remote_properties(const RawAddress& bd_addr, BD_NAME bd_name, DEV_CLASS dev_class,
tBT_DEVICE_TYPE dev_type);
+bool btif_is_interesting_le_service(const bluetooth::Uuid& uuid);
bool check_cod_hid(const RawAddress& bd_addr);
bool check_cod_hid_major(const RawAddress& bd_addr, uint32_t cod);
diff --git a/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h
index 0c1043faae..01432bade6 100644
--- a/system/btif/include/btif_storage.h
+++ b/system/btif/include/btif_storage.h
@@ -446,6 +446,7 @@ bt_status_t btif_storage_set_hid_connection_policy(const tAclLinkSpec& link_spec
bt_status_t btif_storage_get_hid_connection_policy(const tAclLinkSpec& link_spec,
bool* reconnect_allowed);
+void btif_storage_migrate_services();
/******************************************************************************
* Exported for unit tests
*****************************************************************************/
diff --git a/system/btif/src/btif_core.cc b/system/btif/src/btif_core.cc
index f0d06373b6..8e481daed0 100644
--- a/system/btif/src/btif_core.cc
+++ b/system/btif/src/btif_core.cc
@@ -134,7 +134,12 @@ int btif_is_enabled(void) {
return (!btif_is_dut_mode()) && (stack_manager_get_interface()->get_stack_is_running());
}
-void btif_init_ok() { btif_dm_load_ble_local_keys(); }
+void btif_init_ok() {
+ btif_dm_load_ble_local_keys();
+ if (com::android::bluetooth::flags::separate_service_storage()) {
+ btif_storage_migrate_services();
+ }
+}
/*******************************************************************************
*
@@ -290,7 +295,7 @@ void btif_dut_mode_send(uint16_t opcode, uint8_t* buf, uint8_t len) {
****************************************************************************/
static bt_status_t btif_in_get_adapter_properties(void) {
- const static uint32_t NUM_ADAPTER_PROPERTIES = 5;
+ static const uint32_t NUM_ADAPTER_PROPERTIES = 5;
bt_property_t properties[NUM_ADAPTER_PROPERTIES];
uint32_t num_props = 0;
@@ -340,12 +345,13 @@ static bt_status_t btif_in_get_adapter_properties(void) {
}
static bt_status_t btif_in_get_remote_device_properties(RawAddress* bd_addr) {
- bt_property_t remote_properties[8];
+ bt_property_t remote_properties[9];
uint32_t num_props = 0;
bt_bdname_t name, alias;
uint32_t cod, devtype;
Uuid remote_uuids[BT_MAX_NUM_UUIDS];
+ Uuid remote_uuids_le[BT_MAX_NUM_UUIDS];
memset(remote_properties, 0, sizeof(remote_properties));
BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_BDNAME, sizeof(name),
@@ -369,10 +375,17 @@ static bt_status_t btif_in_get_remote_device_properties(RawAddress* bd_addr) {
num_props++;
BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_UUIDS, sizeof(remote_uuids),
- remote_uuids);
+ &remote_uuids);
btif_storage_get_remote_device_property(bd_addr, &remote_properties[num_props]);
num_props++;
+ if (com::android::bluetooth::flags::separate_service_storage()) {
+ BTIF_STORAGE_FILL_PROPERTY(&remote_properties[num_props], BT_PROPERTY_UUIDS_LE,
+ sizeof(remote_uuids_le), &remote_uuids_le);
+ btif_storage_get_remote_device_property(bd_addr, &remote_properties[num_props]);
+ num_props++;
+ }
+
GetInterfaceToProfiles()->events->invoke_remote_device_properties_cb(
BT_STATUS_SUCCESS, *bd_addr, num_props, remote_properties);
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index eda581d81b..6f83aee781 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -1517,15 +1517,16 @@ static void btif_dm_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH*
}
/* Returns true if |uuid| should be passed as device property */
-static bool btif_is_interesting_le_service(bluetooth::Uuid uuid) {
+bool btif_is_interesting_le_service(const bluetooth::Uuid& uuid) {
return uuid.As16Bit() == UUID_SERVCLASS_LE_HID || uuid == UUID_HEARING_AID || uuid == UUID_VC ||
uuid == UUID_CSIS || uuid == UUID_LE_AUDIO || uuid == UUID_LE_MIDI || uuid == UUID_HAS ||
uuid == UUID_BASS || uuid == UUID_BATTERY || uuid == ANDROID_HEADTRACKER_SERVICE_UUID;
}
-static bt_status_t btif_get_existing_uuids(RawAddress* bd_addr, Uuid* existing_uuids) {
+static bt_status_t btif_get_existing_uuids(RawAddress* bd_addr, Uuid* existing_uuids,
+ bt_property_type_t property_type = BT_PROPERTY_UUIDS) {
bt_property_t tmp_prop;
- BTIF_STORAGE_FILL_PROPERTY(&tmp_prop, BT_PROPERTY_UUIDS, sizeof(*existing_uuids), existing_uuids);
+ BTIF_STORAGE_FILL_PROPERTY(&tmp_prop, property_type, sizeof(*existing_uuids), existing_uuids);
return btif_storage_get_remote_device_property(bd_addr, &tmp_prop);
}
@@ -1537,9 +1538,10 @@ static bool btif_is_gatt_service_discovery_post_pairing(const RawAddress bd_addr
(pairing_cb.gatt_over_le == btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED);
}
-static void btif_merge_existing_uuids(RawAddress& addr, std::set<Uuid>* uuids) {
+static void btif_merge_existing_uuids(RawAddress& addr, std::set<Uuid>* uuids,
+ bt_property_type_t property_type = BT_PROPERTY_UUIDS) {
Uuid existing_uuids[BT_MAX_NUM_UUIDS] = {};
- bt_status_t lookup_result = btif_get_existing_uuids(&addr, existing_uuids);
+ bt_status_t lookup_result = btif_get_existing_uuids(&addr, existing_uuids, property_type);
if (lookup_result == BT_STATUS_FAIL) {
return;
@@ -1550,18 +1552,14 @@ static void btif_merge_existing_uuids(RawAddress& addr, std::set<Uuid>* uuids) {
if (btif_should_ignore_uuid(uuid)) {
continue;
}
- if (btif_is_interesting_le_service(uuid)) {
- log::info("interesting le service {} insert", uuid.ToString());
- uuids->insert(uuid);
- }
+
+ uuids->insert(uuid);
}
}
static void btif_on_service_discovery_results(RawAddress bd_addr,
const std::vector<bluetooth::Uuid>& uuids_param,
tBTA_STATUS result) {
- bt_property_t prop;
- std::vector<uint8_t> property_value;
std::set<Uuid> uuids;
bool a2dp_sink_capable = false;
@@ -1589,8 +1587,12 @@ static void btif_on_service_discovery_results(RawAddress bd_addr,
pairing_cb.sdp_over_classic = btif_dm_pairing_cb_t::ServiceDiscoveryState::FINISHED;
}
- prop.type = BT_PROPERTY_UUIDS;
- prop.len = 0;
+ std::vector<uint8_t> bredr_property_value;
+ std::vector<uint8_t> le_property_value;
+ bt_property_t uuid_props[2] = {};
+ bt_property_t& bredr_prop = uuid_props[0];
+ bt_property_t& le_prop = uuid_props[1];
+
if ((result == BTA_SUCCESS) && !uuids_param.empty()) {
log::info("New UUIDs for {}:", bd_addr);
for (const auto& uuid : uuids_param) {
@@ -1610,13 +1612,35 @@ static void btif_on_service_discovery_results(RawAddress bd_addr,
for (auto& uuid : uuids) {
auto uuid_128bit = uuid.To128BitBE();
- property_value.insert(property_value.end(), uuid_128bit.begin(), uuid_128bit.end());
+ bredr_property_value.insert(bredr_property_value.end(), uuid_128bit.begin(),
+ uuid_128bit.end());
if (uuid == UUID_A2DP_SINK) {
a2dp_sink_capable = true;
}
}
- prop.val = (void*)property_value.data();
- prop.len = Uuid::kNumBytes128 * uuids.size();
+
+ bredr_prop = {BT_PROPERTY_UUIDS, static_cast<int>(Uuid::kNumBytes128 * uuids.size()),
+ (void*)bredr_property_value.data()};
+
+ if (com::android::bluetooth::flags::separate_service_storage()) {
+ bt_status_t ret = btif_storage_set_remote_device_property(&bd_addr, &bredr_prop);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote classic services failed", ret);
+
+ std::set<Uuid> le_uuids;
+ if (results_for_bonding_device) {
+ btif_merge_existing_uuids(pairing_cb.static_bdaddr, &le_uuids, BT_PROPERTY_UUIDS_LE);
+ btif_merge_existing_uuids(pairing_cb.bd_addr, &le_uuids, BT_PROPERTY_UUIDS_LE);
+ } else {
+ btif_merge_existing_uuids(bd_addr, &le_uuids, BT_PROPERTY_UUIDS_LE);
+ }
+
+ for (auto& uuid : le_uuids) {
+ auto uuid_128bit = uuid.To128BitBE();
+ le_property_value.insert(le_property_value.end(), uuid_128bit.begin(), uuid_128bit.end());
+ }
+ le_prop = {BT_PROPERTY_UUIDS_LE, static_cast<int>(Uuid::kNumBytes128 * le_uuids.size()),
+ (void*)le_property_value.data()};
+ }
}
bool skip_reporting_wait_for_le = false;
@@ -1649,17 +1673,18 @@ static void btif_on_service_discovery_results(RawAddress bd_addr,
log::info("SDP failed, send {} EIR UUIDs to unblock bonding {}", num_eir_uuids, bd_addr);
for (auto eir_uuid : uuids_iter->second) {
auto uuid_128bit = eir_uuid.To128BitBE();
- property_value.insert(property_value.end(), uuid_128bit.begin(), uuid_128bit.end());
+ bredr_property_value.insert(bredr_property_value.end(), uuid_128bit.begin(),
+ uuid_128bit.end());
}
eir_uuids_cache.erase(uuids_iter);
}
if (num_eir_uuids > 0) {
- prop.val = (void*)property_value.data();
- prop.len = num_eir_uuids * Uuid::kNumBytes128;
+ bredr_prop.val = (void*)bredr_property_value.data();
+ bredr_prop.len = num_eir_uuids * Uuid::kNumBytes128;
} else {
log::warn("SDP failed and we have no EIR UUIDs to report either");
- prop.val = &uuid;
- prop.len = Uuid::kNumBytes128;
+ bredr_prop.val = &uuid;
+ bredr_prop.len = Uuid::kNumBytes128;
}
}
@@ -1677,9 +1702,10 @@ static void btif_on_service_discovery_results(RawAddress bd_addr,
uuids_param.size(), num_eir_uuids));
if (!uuids_param.empty() || num_eir_uuids != 0) {
- /* Also write this to the NVRAM */
- const bt_status_t ret = btif_storage_set_remote_device_property(&bd_addr, &prop);
- ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+ if (!com::android::bluetooth::flags::separate_service_storage()) {
+ const bt_status_t ret = btif_storage_set_remote_device_property(&bd_addr, &bredr_prop);
+ ASSERTC(ret == BT_STATUS_SUCCESS, "storing remote services failed", ret);
+ }
if (skip_reporting_wait_for_le) {
log::info(
@@ -1694,16 +1720,13 @@ static void btif_on_service_discovery_results(RawAddress bd_addr,
}
/* Send the event to the BTIF */
- GetInterfaceToProfiles()->events->invoke_remote_device_properties_cb(BT_STATUS_SUCCESS, bd_addr,
- 1, &prop);
+ GetInterfaceToProfiles()->events->invoke_remote_device_properties_cb(
+ BT_STATUS_SUCCESS, bd_addr, ARRAY_SIZE(uuid_props), uuid_props);
}
}
static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid>& services,
bool is_transport_le) {
- std::vector<bt_property_t> prop;
- std::vector<uint8_t> property_value;
- std::set<Uuid> uuids;
RawAddress static_addr_copy = pairing_cb.static_bdaddr;
bool lea_supported = is_le_audio_capable_during_service_discovery(bd_addr);
@@ -1739,6 +1762,7 @@ static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid
BTM_LogHistory(kBtmLogTag, bd_addr, "Discovered GATT services using SDP transport");
}
+ std::set<Uuid> uuids;
for (Uuid uuid : services) {
if (btif_is_interesting_le_service(uuid)) {
if (btif_should_ignore_uuid(uuid)) {
@@ -1767,46 +1791,28 @@ static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid
log::info("Will return Classic SDP results, if done, to unblock bonding");
}
- Uuid existing_uuids[BT_MAX_NUM_UUIDS] = {};
-
- // Look up UUIDs using pseudo address (either RPA or static address)
- bt_status_t existing_lookup_result = btif_get_existing_uuids(&bd_addr, existing_uuids);
-
- if (existing_lookup_result != BT_STATUS_FAIL) {
- log::info("Got some existing UUIDs by address {}", bd_addr);
-
- for (int i = 0; i < BT_MAX_NUM_UUIDS; i++) {
- Uuid uuid = existing_uuids[i];
- if (uuid.IsEmpty()) {
- continue;
- }
- uuids.insert(uuid);
+ if (!com::android::bluetooth::flags::separate_service_storage()) {
+ // Look up UUIDs using pseudo address (either RPA or static address)
+ btif_merge_existing_uuids(bd_addr, &uuids);
+ if (bd_addr != static_addr_copy) {
+ // Look up UUID using static address, if different than sudo address
+ btif_merge_existing_uuids(static_addr_copy, &uuids);
}
}
- if (bd_addr != static_addr_copy) {
- // Look up UUID using static address, if different than sudo address
- existing_lookup_result = btif_get_existing_uuids(&static_addr_copy, existing_uuids);
- if (existing_lookup_result != BT_STATUS_FAIL) {
- log::info("Got some existing UUIDs by static address {}", static_addr_copy);
- for (int i = 0; i < BT_MAX_NUM_UUIDS; i++) {
- Uuid uuid = existing_uuids[i];
- if (uuid.IsEmpty()) {
- continue;
- }
- uuids.insert(uuid);
- }
- }
- }
+ std::vector<bt_property_t> prop;
+ std::vector<uint8_t> property_value;
for (auto& uuid : uuids) {
auto uuid_128bit = uuid.To128BitBE();
property_value.insert(property_value.end(), uuid_128bit.begin(), uuid_128bit.end());
}
- prop.push_back(bt_property_t{BT_PROPERTY_UUIDS,
- static_cast<int>(Uuid::kNumBytes128 * uuids.size()),
- (void*)property_value.data()});
+ prop.push_back(bt_property_t{
+ (com::android::bluetooth::flags::separate_service_storage() && is_transport_le)
+ ? BT_PROPERTY_UUIDS_LE
+ : BT_PROPERTY_UUIDS,
+ static_cast<int>(Uuid::kNumBytes128 * uuids.size()), (void*)property_value.data()});
/* Also write this to the NVRAM */
bt_status_t ret = btif_storage_set_remote_device_property(&bd_addr, &prop[0]);
@@ -1817,8 +1823,7 @@ static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid
* send them with rest of SDP results in on_service_discovery_results */
return;
} else {
- if (pairing_cb.sdp_over_classic == btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED &&
- com::android::bluetooth::flags::bta_dm_discover_both()) {
+ if (pairing_cb.sdp_over_classic == btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED) {
/* Don't report services yet, they will be reported together once SDP
* finishes. */
log::info("will report services later, with SDP results {}", bd_addr);
@@ -1826,6 +1831,32 @@ static void btif_on_gatt_results(RawAddress bd_addr, std::vector<bluetooth::Uuid
}
}
+ if (!com::android::bluetooth::flags::separate_service_storage()) {
+ /* Send the event to the BTIF */
+ GetInterfaceToProfiles()->events->invoke_remote_device_properties_cb(BT_STATUS_SUCCESS, bd_addr,
+ prop.size(), prop.data());
+ return;
+ }
+
+ std::set<Uuid> bredr_uuids;
+ // Look up UUIDs using pseudo address (either RPA or static address)
+ btif_merge_existing_uuids(bd_addr, &bredr_uuids);
+ if (bd_addr != static_addr_copy) {
+ // Look up UUID using static address, if different than sudo address
+ btif_merge_existing_uuids(static_addr_copy, &bredr_uuids);
+ }
+
+ std::vector<uint8_t> bredr_property_value;
+
+ for (auto& uuid : bredr_uuids) {
+ auto uuid_128bit = uuid.To128BitBE();
+ bredr_property_value.insert(bredr_property_value.end(), uuid_128bit.begin(), uuid_128bit.end());
+ }
+
+ prop.push_back(bt_property_t{BT_PROPERTY_UUIDS,
+ static_cast<int>(Uuid::kNumBytes128 * bredr_uuids.size()),
+ (void*)bredr_property_value.data()});
+
/* Send the event to the BTIF */
GetInterfaceToProfiles()->events->invoke_remote_device_properties_cb(BT_STATUS_SUCCESS, bd_addr,
prop.size(), prop.data());
@@ -2517,6 +2548,9 @@ void btif_dm_cancel_bond(const RawAddress bd_addr) {
** 2. special handling for HID devices
*/
if (is_bonding_or_sdp()) {
+ // clear sdp_attempts
+ pairing_cb.sdp_attempts = 0;
+
if (com::android::bluetooth::flags::ignore_unrelated_cancel_bond() &&
(pairing_cb.bd_addr != bd_addr)) {
log::warn("Ignoring bond cancel for unrelated device: {} pairing: {}", bd_addr,
diff --git a/system/btif/src/btif_storage.cc b/system/btif/src/btif_storage.cc
index e51756483c..4704362f2c 100644
--- a/system/btif/src/btif_storage.cc
+++ b/system/btif/src/btif_storage.cc
@@ -47,6 +47,7 @@
#include "btif/include/btif_api.h"
#include "btif/include/btif_config.h"
+#include "btif/include/btif_dm.h"
#include "btif/include/btif_util.h"
#include "btif/include/core_callbacks.h"
#include "btif/include/stack_manager_t.h"
@@ -179,15 +180,18 @@ static bool prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) {
case BT_PROPERTY_TYPE_OF_DEVICE:
btif_config_set_int(bdstr, BTIF_STORAGE_KEY_DEV_TYPE, *reinterpret_cast<int*>(prop->val));
break;
- case BT_PROPERTY_UUIDS: {
+ case BT_PROPERTY_UUIDS:
+ case BT_PROPERTY_UUIDS_LE: {
std::string val;
size_t cnt = (prop->len) / sizeof(Uuid);
for (size_t i = 0; i < cnt; i++) {
val += (reinterpret_cast<Uuid*>(prop->val) + i)->ToString() + " ";
}
- btif_config_set_str(bdstr, BTIF_STORAGE_KEY_REMOTE_SERVICE, val);
- break;
- }
+ std::string key = (prop->type == BT_PROPERTY_UUIDS_LE) ? BTIF_STORAGE_KEY_REMOTE_SERVICE_LE
+ : BTIF_STORAGE_KEY_REMOTE_SERVICE;
+ btif_config_set_str(bdstr, key, val);
+ } break;
+
case BT_PROPERTY_REMOTE_VERSION_INFO: {
bt_remote_version_t* info = reinterpret_cast<bt_remote_version_t*>(prop->val);
@@ -300,10 +304,15 @@ static bool cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) {
reinterpret_cast<int*>(prop->val));
}
break;
- case BT_PROPERTY_UUIDS: {
+ case BT_PROPERTY_UUIDS:
+ case BT_PROPERTY_UUIDS_LE: {
char value[1280];
int size = sizeof(value);
- if (btif_config_get_str(bdstr, BTIF_STORAGE_KEY_REMOTE_SERVICE, value, &size)) {
+
+ std::string key = (prop->type == BT_PROPERTY_UUIDS_LE) ? BTIF_STORAGE_KEY_REMOTE_SERVICE_LE
+ : BTIF_STORAGE_KEY_REMOTE_SERVICE;
+
+ if (btif_config_get_str(bdstr, key, value, &size)) {
Uuid* p_uuid = reinterpret_cast<Uuid*>(prop->val);
size_t num_uuids = btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS);
prop->len = num_uuids * sizeof(Uuid);
@@ -938,13 +947,14 @@ bt_status_t btif_storage_load_bonded_devices(void) {
uint32_t i = 0;
bt_property_t adapter_props[6];
uint32_t num_props = 0;
- bt_property_t remote_properties[10];
+ bt_property_t remote_properties[11];
RawAddress addr;
bt_bdname_t name, alias, model_name;
bt_scan_mode_t mode;
uint32_t disc_timeout;
Uuid local_uuids[BT_MAX_NUM_UUIDS];
Uuid remote_uuids[BT_MAX_NUM_UUIDS];
+ Uuid remote_uuids_le[BT_MAX_NUM_UUIDS];
bt_status_t status;
remove_devices_with_sample_ltk();
@@ -1026,10 +1036,16 @@ bt_status_t btif_storage_load_bonded_devices(void) {
sizeof(devtype), &remote_properties[num_props]);
num_props++;
- btif_storage_get_remote_prop(p_remote_addr, BT_PROPERTY_UUIDS, remote_uuids,
+ btif_storage_get_remote_prop(p_remote_addr, BT_PROPERTY_UUIDS, &remote_uuids,
sizeof(remote_uuids), &remote_properties[num_props]);
num_props++;
+ if (com::android::bluetooth::flags::separate_service_storage()) {
+ btif_storage_get_remote_prop(p_remote_addr, BT_PROPERTY_UUIDS_LE, &remote_uuids_le,
+ sizeof(remote_uuids_le), &remote_properties[num_props]);
+ num_props++;
+ }
+
// Floss needs appearance for metrics purposes
uint16_t appearance = 0;
if (btif_storage_get_remote_prop(p_remote_addr, BT_PROPERTY_APPEARANCE, &appearance,
@@ -1438,6 +1454,48 @@ void btif_storage_remove_gatt_cl_db_hash(const RawAddress& bd_addr) {
bd_addr));
}
+// TODO(b/369381361) Remove this function after all devices are migrated
+void btif_storage_migrate_services() {
+ for (const auto& mac_address : btif_config_get_paired_devices()) {
+ auto addr_str = mac_address.ToString();
+
+ int device_type = BT_DEVICE_TYPE_UNKNOWN;
+ btif_config_get_int(addr_str, BTIF_STORAGE_KEY_DEV_TYPE, &device_type);
+
+ if ((device_type == BT_DEVICE_TYPE_BREDR) ||
+ btif_config_exist(addr_str, BTIF_STORAGE_KEY_REMOTE_SERVICE_LE)) {
+ /* Classic only, or already migrated entries don't need migration */
+ continue;
+ }
+
+ bt_property_t remote_uuids_prop;
+ Uuid remote_uuids[BT_MAX_NUM_UUIDS];
+ BTIF_STORAGE_FILL_PROPERTY(&remote_uuids_prop, BT_PROPERTY_UUIDS, sizeof(remote_uuids),
+ remote_uuids);
+ btif_storage_get_remote_device_property(&mac_address, &remote_uuids_prop);
+
+ log::info("Will migrate Services => ServicesLe for {}", mac_address.ToStringForLogging());
+
+ std::vector<uint8_t> property_value;
+ for (auto& uuid : remote_uuids) {
+ if (!btif_is_interesting_le_service(uuid)) {
+ continue;
+ }
+
+ log::info("interesting LE service: {}", uuid);
+ auto uuid_128bit = uuid.To128BitBE();
+ property_value.insert(property_value.end(), uuid_128bit.begin(), uuid_128bit.end());
+ }
+
+ bt_property_t le_uuids_prop{BT_PROPERTY_UUIDS_LE, static_cast<int>(property_value.size()),
+ (void*)property_value.data()};
+
+ /* Write LE services to storage */
+ btif_storage_set_remote_device_property(&mac_address, &le_uuids_prop);
+ log::info("Migration finished for {}", mac_address.ToStringForLogging());
+ }
+}
+
void btif_debug_linkkey_type_dump(int fd) {
dprintf(fd, "\nLink Key Types:\n");
for (const auto& bd_addr : btif_config_get_paired_devices()) {
diff --git a/system/btif/src/btif_util.cc b/system/btif/src/btif_util.cc
index 85c0069eaa..c6cf544d4a 100644
--- a/system/btif/src/btif_util.cc
+++ b/system/btif/src/btif_util.cc
@@ -129,6 +129,7 @@ std::string dump_property_type(bt_property_type_t type) {
CASE_RETURN_STRING(BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT);
CASE_RETURN_STRING(BT_PROPERTY_ADAPTER_BONDED_DEVICES);
CASE_RETURN_STRING(BT_PROPERTY_REMOTE_FRIENDLY_NAME);
+ CASE_RETURN_STRING(BT_PROPERTY_UUIDS_LE);
default:
RETURN_UNKNOWN_TYPE_STRING(bt_property_type_t, type);
}
diff --git a/system/btif/test/btif_core_test.cc b/system/btif/test/btif_core_test.cc
index 66881a92d8..1bffc9ce3a 100644
--- a/system/btif/test/btif_core_test.cc
+++ b/system/btif/test/btif_core_test.cc
@@ -320,6 +320,7 @@ TEST_F(BtifUtilsTest, dump_property_type) {
"BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT"),
std::make_pair(BT_PROPERTY_ADAPTER_BONDED_DEVICES, "BT_PROPERTY_ADAPTER_BONDED_DEVICES"),
std::make_pair(BT_PROPERTY_REMOTE_FRIENDLY_NAME, "BT_PROPERTY_REMOTE_FRIENDLY_NAME"),
+ std::make_pair(BT_PROPERTY_UUIDS_LE, "BT_PROPERTY_UUIDS_LE"),
};
for (const auto& type : types) {
EXPECT_TRUE(dump_property_type(type.first).starts_with(type.second));
diff --git a/system/conf/interop_database.conf b/system/conf/interop_database.conf
index f798e328c4..94ef06e885 100644
--- a/system/conf/interop_database.conf
+++ b/system/conf/interop_database.conf
@@ -105,6 +105,16 @@ C8:FD:19 = Address_Based
0C:A6:94 = Address_Based
00:0f:59:50:00:00-00:0f:59:6f:ff:ff = Address_Range_Based
+# Some devices only respond to read SIRK request via GATT_READ_CHAR_VALUE
+# disabling GATT_READ_BY_TYPE for SIRK read for those devices.
+# 48:73:CB ==> Name: Redmi buds
+# 00:02:3C ==> Name: Zen Air Pro
+# 14:0A:29 ==> Name: Redmi Buds 5 Pro
+[INTEROP_DISABLE_SIRK_READ_BY_TYPE]
+48:73:CB = Address_Based
+00:02:3C = Address_Based
+14:0A:29 = Address_Based
+
# Disable automatic pairing with headsets/car-kits
# Some car kits do not react kindly to a failed pairing attempt and
# do not allow immediate re-pairing. Denylist these so that the initial
@@ -883,3 +893,8 @@ BSK10 = Name_Based
[INTEROP_DISABLE_HF_PROFILE]
JBL Flip 5 = Name_Based
JBL Flip 6 = Name_Based
+
+# Some carkits don't support rejecting notifications when addressed player changed.
+[INTEROP_ADDRESSED_PLAYER_CHANGE_REJECT]
+4c:3f:d3 = Address_Based
+e8:d5:2b = Address_Based
diff --git a/system/device/include/interop.h b/system/device/include/interop.h
index b23900888b..a19c5fbaae 100644
--- a/system/device/include/interop.h
+++ b/system/device/include/interop.h
@@ -48,6 +48,9 @@ typedef enum {
// levels or general lack of controlability.
INTEROP_DISABLE_ABSOLUTE_VOLUME,
+ // Devices requiring this read characteristics via GATT_READ_CHAR_VALUE
+ INTEROP_DISABLE_SIRK_READ_BY_TYPE,
+
// Disable automatic pairing with headsets/car-kits
// Some car kits do not react kindly to a failed pairing attempt and
// do not allow immediate re-pairing. Rejectlist these so that the initial
@@ -365,6 +368,9 @@ typedef enum {
// Some devices claim to support HFP in EIR but does not actually support it.
INTEROP_DISABLE_HF_PROFILE,
+ // Some carkits don't support rejecting notifications when addressed player changed.
+ INTEROP_ADDRESSED_PLAYER_CHANGE_REJECT,
+
END_OF_INTEROP_LIST
} interop_feature_t;
diff --git a/system/device/src/interop.cc b/system/device/src/interop.cc
index 354a9e1a65..614e3c8981 100644
--- a/system/device/src/interop.cc
+++ b/system/device/src/interop.cc
@@ -327,6 +327,7 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
CASE_RETURN_STR(INTEROP_DISABLE_LE_SECURE_CONNECTIONS)
CASE_RETURN_STR(INTEROP_AUTO_RETRY_PAIRING)
CASE_RETURN_STR(INTEROP_DISABLE_ABSOLUTE_VOLUME)
+ CASE_RETURN_STR(INTEROP_DISABLE_SIRK_READ_BY_TYPE)
CASE_RETURN_STR(INTEROP_DISABLE_AUTO_PAIRING)
CASE_RETURN_STR(INTEROP_KEYBOARD_REQUIRES_FIXED_PIN)
CASE_RETURN_STR(INTEROP_2MBPS_LINK_ONLY)
@@ -394,6 +395,7 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
CASE_RETURN_STR(INTEROP_HOGP_LONG_REPORT);
CASE_RETURN_STR(INTEROP_HOGP_FORCE_MTU_EXCHANGE);
CASE_RETURN_STR(INTEROP_DISABLE_HF_PROFILE);
+ CASE_RETURN_STR(INTEROP_ADDRESSED_PLAYER_CHANGE_REJECT);
}
return UNKNOWN_INTEROP_FEATURE;
}
diff --git a/system/gd/hci/distance_measurement_manager.cc b/system/gd/hci/distance_measurement_manager.cc
index 696f33e621..f5ef4fbec5 100644
--- a/system/gd/hci/distance_measurement_manager.cc
+++ b/system/gd/hci/distance_measurement_manager.cc
@@ -32,6 +32,7 @@
#include "hci/event_checkers.h"
#include "hci/hci_layer.h"
#include "module.h"
+#include "os/alarm.h"
#include "os/handler.h"
#include "os/repeating_alarm.h"
#include "packet/packet_view.h"
@@ -84,6 +85,7 @@ static constexpr uint16_t kInvalidConnInterval = 0; // valid value is from 0x00
static constexpr uint16_t kDefaultRasMtu = 247; // Section 3.1.2 of RAP 1.0
static constexpr uint8_t kAttHeaderSize = 5; // Section 3.2.2.1 of RAS 1.0
static constexpr uint8_t kRasSegmentHeaderSize = 1;
+static constexpr uint16_t kEnableSecurityTimeoutMs = 10000; // 10s
struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
struct CsProcedureData {
@@ -216,6 +218,7 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
PacketViewForRecombination segment_data_;
uint16_t conn_interval_ = kInvalidConnInterval;
uint8_t procedure_sequence_after_enable = -1;
+ std::unique_ptr<os::Alarm> enable_security_timeout_alarm = nullptr;
};
bool get_free_config_id(uint16_t connection_handle, uint8_t& config_id) {
@@ -683,10 +686,12 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
return;
}
switch (event.GetSubeventCode()) {
- case hci::SubeventCode::LE_CS_TEST_END_COMPLETE:
- case hci::SubeventCode::LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE: {
+ case hci::SubeventCode::LE_CS_TEST_END_COMPLETE: {
log::warn("Unhandled subevent {}", hci::SubeventCodeText(event.GetSubeventCode()));
} break;
+ case hci::SubeventCode::LE_CS_READ_REMOTE_FAE_TABLE_COMPLETE: {
+ on_cs_read_remote_fae_table_complete(LeCsReadRemoteFaeTableCompleteView::Create(event));
+ } break;
case hci::SubeventCode::LE_CS_SUBEVENT_RESULT_CONTINUE:
case hci::SubeventCode::LE_CS_SUBEVENT_RESULT: {
on_cs_subevent(event);
@@ -747,6 +752,11 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
handler_->BindOnceOn(this, &impl::on_cs_set_default_settings_complete));
}
+ void send_le_cs_read_remote_fae_table(uint16_t connection_handle) const {
+ hci_layer_->EnqueueCommand(LeCsReadRemoteFaeTableBuilder::Create(connection_handle),
+ handler_->BindOnce(check_status<LeCsReadRemoteFaeTableStatusView>));
+ }
+
void send_le_cs_create_config(uint16_t connection_handle, uint8_t config_id) {
if (cs_requester_trackers_.find(connection_handle) == cs_requester_trackers_.end()) {
log::warn("no cs tracker found for {}", connection_handle);
@@ -938,6 +948,12 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
req_it->second.remote_num_antennas_supported_ = event_view.GetNumAntennasSupported();
req_it->second.retry_counter_for_create_config = 0;
req_it->second.remote_supported_sw_time_ = event_view.GetTSwTimeSupported();
+
+ if (event_view.GetOptionalSubfeaturesSupported().no_frequency_actuation_error_ == 0) {
+ log::debug("read remote fae as the no_fae is false.");
+ send_le_cs_read_remote_fae_table(connection_handle);
+ }
+
send_le_cs_create_config(connection_handle, req_it->second.requesting_config_id);
}
log::info(
@@ -963,19 +979,39 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
}
}
+ static void on_cs_read_remote_fae_table_complete(LeCsReadRemoteFaeTableCompleteView event_view) {
+ if (!event_view.IsValid()) {
+ log::warn("Get invalid LeCsReadRemoteFaeTableCompleteView");
+ return;
+ }
+ if (event_view.GetStatus() != ErrorCode::SUCCESS) {
+ log::warn("Received LeCsReadRemoteFaeTableCompleteView with error code {}",
+ ErrorCodeText(event_view.GetStatus()));
+ // not critical, do nothing here.
+ }
+ }
+
void on_cs_security_enable_complete(LeCsSecurityEnableCompleteView event_view) {
if (!event_view.IsValid()) {
log::warn("Get invalid LeCsSecurityEnableCompleteView");
return;
}
uint16_t connection_handle = event_view.GetConnectionHandle();
+ auto req_it = cs_requester_trackers_.find(connection_handle);
+ if (req_it != cs_requester_trackers_.end() &&
+ req_it->second.state == CsTrackerState::WAIT_FOR_SECURITY_ENABLED &&
+ req_it->second.enable_security_timeout_alarm != nullptr) {
+ log::debug("cancel alarm for security enable cmd.");
+ req_it->second.enable_security_timeout_alarm->Cancel();
+ req_it->second.enable_security_timeout_alarm = nullptr;
+ }
if (event_view.GetStatus() != ErrorCode::SUCCESS) {
std::string error_code = ErrorCodeText(event_view.GetStatus());
log::warn("Received LeCsSecurityEnableCompleteView with error code {}", error_code);
handle_cs_setup_failure(connection_handle, REASON_INTERNAL_ERROR);
return;
}
- auto req_it = cs_requester_trackers_.find(connection_handle);
+
if (req_it != cs_requester_trackers_.end() &&
req_it->second.state == CsTrackerState::WAIT_FOR_SECURITY_ENABLED) {
send_le_cs_set_procedure_parameters(event_view.GetConnectionHandle(),
@@ -1055,8 +1091,25 @@ struct DistanceMeasurementManager::impl : bluetooth::hal::RangingHalCallback {
// send the cmd from the BLE central only.
send_le_cs_security_enable(connection_handle, live_tracker->local_start);
} else {
- // TODO: else set a timeout alarm to make sure the remote would trigger the cmd.
live_tracker->state = CsTrackerState::WAIT_FOR_SECURITY_ENABLED;
+ if (live_tracker->local_start) {
+ if (live_tracker->enable_security_timeout_alarm == nullptr) {
+ live_tracker->enable_security_timeout_alarm = std::make_unique<os::Alarm>(handler_);
+ }
+ live_tracker->enable_security_timeout_alarm->Schedule(
+ common::Bind(&impl::le_cs_enable_security_timeout, common::Unretained(this),
+ connection_handle),
+ std::chrono::milliseconds(kEnableSecurityTimeoutMs));
+ }
+ }
+ }
+
+ void le_cs_enable_security_timeout(uint16_t connection_handle) {
+ auto req_it = cs_requester_trackers_.find(connection_handle);
+ if (req_it != cs_requester_trackers_.end()) {
+ log::info("security enable cmd is timeout, stop current session.");
+ handle_cs_setup_failure(connection_handle,
+ DistanceMeasurementErrorCode::REASON_INTERNAL_ERROR);
}
}
diff --git a/system/gd/hci/le_advertising_manager.h b/system/gd/hci/le_advertising_manager.h
index 55245a5cfa..fe614861e2 100644
--- a/system/gd/hci/le_advertising_manager.h
+++ b/system/gd/hci/le_advertising_manager.h
@@ -47,8 +47,8 @@ class AdvertisingConfig {
public:
std::vector<GapData> advertisement;
std::vector<GapData> scan_response;
- uint16_t interval_min;
- uint16_t interval_max;
+ uint32_t interval_min;
+ uint32_t interval_max;
AdvertisingType advertising_type;
AdvertiserAddressType requested_advertiser_address_type;
PeerAddressType peer_address_type;
diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs
index 761f9483f3..b0b74193f4 100644
--- a/system/gd/rust/linux/stack/src/bluetooth.rs
+++ b/system/gd/rust/linux/stack/src/bluetooth.rs
@@ -374,7 +374,7 @@ struct BluetoothDeviceContext {
pub info: BluetoothDevice,
pub last_seen: Instant,
pub properties: HashMap<BtPropertyType, BluetoothProperty>,
- pub is_hh_connected: bool,
+ pub is_initiated_hh_connection: bool,
/// If user wants to connect to all profiles, when new profiles are discovered we will also try
/// to connect them.
@@ -398,7 +398,7 @@ impl BluetoothDeviceContext {
info,
last_seen,
properties: HashMap::new(),
- is_hh_connected: false,
+ is_initiated_hh_connection: false,
connect_to_new_profiles: false,
};
device.update_properties(&properties);
@@ -1302,8 +1302,11 @@ impl Bluetooth {
|| self.pending_create_bond.is_some()
}
- pub fn is_hh_connected(&self, device_address: &RawAddress) -> bool {
- self.remote_devices.get(&device_address).map_or(false, |context| context.is_hh_connected)
+ /// Checks whether a Hid/Hog connection is being established or active.
+ pub fn is_initiated_hh_connection(&self, device_address: &RawAddress) -> bool {
+ self.remote_devices
+ .get(&device_address)
+ .map_or(false, |context| context.is_initiated_hh_connection)
}
/// Checks whether the list of device properties contains some UUID we should connect now
@@ -3018,12 +3021,16 @@ impl BtifHHCallbacks for Bluetooth {
let tx = self.tx.clone();
self.remote_devices.entry(address).and_modify(|context| {
- if context.is_hh_connected && state != BthhConnectionState::Connected {
+ if context.is_initiated_hh_connection
+ && (state != BthhConnectionState::Connected
+ && state != BthhConnectionState::Connecting)
+ {
tokio::spawn(async move {
let _ = tx.send(Message::ProfileDisconnected(address)).await;
});
}
- context.is_hh_connected = state == BthhConnectionState::Connected;
+ context.is_initiated_hh_connection =
+ state == BthhConnectionState::Connected || state == BthhConnectionState::Connecting;
});
if BtBondState::Bonded != self.get_bond_state_by_addr(&address)
diff --git a/system/gd/rust/linux/stack/src/lib.rs b/system/gd/rust/linux/stack/src/lib.rs
index 8027c1c61f..6cccf41219 100644
--- a/system/gd/rust/linux/stack/src/lib.rs
+++ b/system/gd/rust/linux/stack/src/lib.rs
@@ -619,7 +619,7 @@ impl Stack {
// to know whether a socket is open or not.
if bluetooth_gatt.lock().unwrap().get_connected_applications(&addr)
== vec![bas_app_uuid]
- && !bluetooth.lock().unwrap().is_hh_connected(&addr)
+ && !bluetooth.lock().unwrap().is_initiated_hh_connection(&addr)
&& bluetooth_media.lock().unwrap().get_connected_profiles(&addr).is_empty()
{
info!(
diff --git a/system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc b/system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc
index 2bfa893d80..0ae488cd9e 100644
--- a/system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc
+++ b/system/gd/rust/topshim/gatt/gatt_ble_scanner_shim.cc
@@ -248,9 +248,7 @@ void BleScannerIntf::MsftAdvMonitorEnable(bool enable) {
void BleScannerIntf::SetScanParameters(uint8_t scanner_id, uint8_t scan_type,
uint16_t scan_interval, uint16_t scan_window,
uint8_t scan_phy) {
- scanner_intf_->SetScanParameters(
- scanner_id, scan_type, scan_interval, scan_window, scan_phy,
- base::Bind(&BleScannerIntf::OnStatusCallback, base::Unretained(this), scanner_id));
+ scanner_intf_->SetScanParameters(scanner_id, scan_type, scan_interval, scan_window, scan_phy);
}
void BleScannerIntf::BatchscanConfigStorage(uint8_t scanner_id, int32_t batch_scan_full_max,
diff --git a/system/gd/storage/config_keys.h b/system/gd/storage/config_keys.h
index 4629a494ba..d3659b6a96 100644
--- a/system/gd/storage/config_keys.h
+++ b/system/gd/storage/config_keys.h
@@ -111,6 +111,7 @@
#define BTIF_STORAGE_KEY_PIN_LENGTH "PinLength"
#define BTIF_STORAGE_KEY_PRODUCT_ID "ProductId"
#define BTIF_STORAGE_KEY_REMOTE_SERVICE "Service"
+#define BTIF_STORAGE_KEY_REMOTE_SERVICE_LE "ServiceLe"
#define BTIF_STORAGE_KEY_REMOTE_VER_MFCT "Manufacturer"
#define BTIF_STORAGE_KEY_REMOTE_VER_SUBVER "LmpSubVer"
#define BTIF_STORAGE_KEY_REMOTE_VER_VER "LmpVer"
diff --git a/system/include/hardware/ble_scanner.h b/system/include/hardware/ble_scanner.h
index 6adb09d26c..6cf69bbab7 100644
--- a/system/include/hardware/ble_scanner.h
+++ b/system/include/hardware/ble_scanner.h
@@ -137,7 +137,7 @@ public:
/** Sets the LE scan interval and window in units of N*0.625 msec */
virtual void SetScanParameters(int scanner_id, uint8_t scan_type, int scan_interval,
- int scan_window, int scan_phy, Callback cb) = 0;
+ int scan_window, int scan_phy) = 0;
/* Configure the batchscan storage */
virtual void BatchscanConfigStorage(int client_if, int batch_scan_full_max,
diff --git a/system/include/hardware/bluetooth.h b/system/include/hardware/bluetooth.h
index a7a3bb0aa2..fa15353d9f 100644
--- a/system/include/hardware/bluetooth.h
+++ b/system/include/hardware/bluetooth.h
@@ -299,7 +299,7 @@ typedef enum {
*/
BT_PROPERTY_TYPE_OF_DEVICE,
/**
- * Description - Bluetooth Service Record
+ * Description - Bluetooth Service Record, UUIDs on BREDR transport
* Access mode - Only GET.
* Data type - bt_service_record_t
*/
@@ -427,6 +427,14 @@ typedef enum {
*/
BT_PROPERTY_LPP_OFFLOAD_FEATURES,
+ /**
+ * Description - Bluetooth Service 128-bit UUIDs on LE transport
+ * Access mode - Only GET.
+ * Data type - Array of bluetooth::Uuid (Array size inferred from property
+ * length).
+ */
+ BT_PROPERTY_UUIDS_LE,
+
BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP = 0xFF,
} bt_property_type_t;
diff --git a/system/include/hardware/bt_av.h b/system/include/hardware/bt_av.h
index b839cb048f..f7d367bc6d 100644
--- a/system/include/hardware/bt_av.h
+++ b/system/include/hardware/bt_av.h
@@ -75,7 +75,6 @@ typedef enum {
// Add an entry for each sink codec here
BTAV_A2DP_CODEC_INDEX_SINK_SBC = BTAV_A2DP_CODEC_INDEX_SINK_MIN,
BTAV_A2DP_CODEC_INDEX_SINK_AAC,
- BTAV_A2DP_CODEC_INDEX_SINK_LDAC,
BTAV_A2DP_CODEC_INDEX_SINK_OPUS,
BTAV_A2DP_CODEC_INDEX_SINK_MAX,
@@ -184,8 +183,6 @@ struct btav_a2dp_codec_config_t {
return "SBC (Sink)";
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
return "AAC (Sink)";
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- return "LDAC (Sink)";
case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
return "LC3";
case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
diff --git a/system/main/shim/ble_scanner_interface_impl.h b/system/main/shim/ble_scanner_interface_impl.h
index 53c5f0df94..9c57c9b3cc 100644
--- a/system/main/shim/ble_scanner_interface_impl.h
+++ b/system/main/shim/ble_scanner_interface_impl.h
@@ -69,7 +69,7 @@ public:
void MsftAdvMonitorRemove(uint8_t monitor_handle, MsftAdvMonitorRemoveCallback cb) override;
void MsftAdvMonitorEnable(bool enable, MsftAdvMonitorEnableCallback cb) override;
void SetScanParameters(int scanner_id, uint8_t scan_type, int scan_interval, int scan_window,
- int scan_phy, Callback cb) override;
+ int scan_phy) override;
void BatchscanConfigStorage(int client_if, int batch_scan_full_max, int batch_scan_trunc_max,
int batch_scan_notify_threshold, Callback cb) override;
void BatchscanEnable(int scan_mode, int scan_interval, int scan_window, int addr_type,
diff --git a/system/main/shim/le_scanning_manager.cc b/system/main/shim/le_scanning_manager.cc
index 8214dea25c..6aac1add2a 100644
--- a/system/main/shim/le_scanning_manager.cc
+++ b/system/main/shim/le_scanning_manager.cc
@@ -24,6 +24,7 @@
#include <hardware/bluetooth.h>
#include "btif/include/btif_common.h"
+#include "btif/include/btif_dm.h"
#include "hci/address.h"
#include "hci/le_scanning_manager.h"
#include "hci/msft.h"
@@ -35,6 +36,7 @@
#include "main/shim/shim.h"
#include "stack/btm/btm_int_types.h"
#include "stack/include/advertise_data_parser.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/bt_dev_class.h"
#include "stack/include/btm_log_history.h"
#include "stack/include/btm_status.h"
@@ -111,20 +113,6 @@ private:
static_cast<::ScanningCallbacks*>(&default_scanning_callback_);
extern ::ScanningCallbacks* bluetooth::shim::default_scanning_callback;
-void btm_ble_process_adv_pkt_cont_for_inquiry(uint16_t event_type, tBLE_ADDR_TYPE address_type,
- const RawAddress& raw_address, uint8_t primary_phy,
- uint8_t secondary_phy, uint8_t advertising_sid,
- int8_t tx_power, int8_t rssi,
- uint16_t periodic_adv_int,
- std::vector<uint8_t> advertising_data);
-
-extern void btif_update_remote_properties(const RawAddress& bd_addr, BD_NAME bd_name,
- DEV_CLASS dev_class, tBT_DEVICE_TYPE dev_type);
-
-void btm_ble_process_adv_addr(RawAddress& raw_address, tBLE_ADDR_TYPE* address_type);
-
-extern DEV_CLASS btm_ble_get_appearance_as_cod(std::vector<uint8_t> const& data);
-
using bluetooth::shim::BleScannerInterfaceImpl;
void BleScannerInterfaceImpl::Init() {
@@ -312,8 +300,7 @@ void BleScannerInterfaceImpl::OnMsftAdvMonitorEnable(bool enable,
/** Sets the LE scan interval and window in units of N*0.625 msec */
void BleScannerInterfaceImpl::SetScanParameters(int scanner_id, uint8_t scan_type,
- int scan_interval, int scan_window, int scan_phy,
- Callback /* cb */) {
+ int scan_interval, int scan_window, int scan_phy) {
log::info("in shim layer, scannerId={}", scanner_id);
if (BTM_BLE_ISVALID_PARAM(scan_interval, BTM_BLE_SCAN_INT_MIN, BTM_BLE_EXT_SCAN_INT_MAX) &&
BTM_BLE_ISVALID_PARAM(scan_window, BTM_BLE_SCAN_WIN_MIN, BTM_BLE_EXT_SCAN_WIN_MAX)) {
diff --git a/system/pdl/hci/hci_packets.pdl b/system/pdl/hci/hci_packets.pdl
index 3810ffefd0..fcdd255b99 100644
--- a/system/pdl/hci/hci_packets.pdl
+++ b/system/pdl/hci/hci_packets.pdl
@@ -4954,7 +4954,7 @@ struct CsOptionalCsSyncPhysSupported {
struct CsOptionalSubfeaturesSupported {
_reserved_ : 1,
- frequency_actuation_error : 1,
+ no_frequency_actuation_error : 1,
channel_selection_algorithm : 1,
phase_based_ranging : 1,
_reserved_ : 12,
diff --git a/system/profile/avrcp/Android.bp b/system/profile/avrcp/Android.bp
index 6ea0ea1abb..3b3debea5f 100644
--- a/system/profile/avrcp/Android.bp
+++ b/system/profile/avrcp/Android.bp
@@ -121,10 +121,12 @@ cc_fuzz {
"libbluetooth-types",
"libbluetooth_gd",
"libbluetooth_log",
+ "libbtdevice",
"libchrome",
"libcutils",
"libevent",
"liblog",
+ "libosi",
"libstatslog_bt",
"libutils",
],
diff --git a/system/profile/avrcp/device.cc b/system/profile/avrcp/device.cc
index d094108d8a..beaaf6b755 100644
--- a/system/profile/avrcp/device.cc
+++ b/system/profile/avrcp/device.cc
@@ -23,6 +23,7 @@
#include "abstract_message_loop.h"
#include "avrcp_common.h"
+#include "device/include/interop.h"
#include "internal_include/stack_config.h"
#include "packet/avrcp/avrcp_reject_packet.h"
#include "packet/avrcp/general_reject_packet.h"
@@ -736,7 +737,9 @@ void Device::AddressedPlayerNotificationResponse(uint8_t label, bool interim,
if (!interim) {
active_labels_.erase(label);
addr_player_changed_ = Notification(false, 0);
- RejectNotification();
+ if (!interop_match_addr(INTEROP_ADDRESSED_PLAYER_CHANGE_REJECT, &address_)) {
+ RejectNotification();
+ }
}
}
diff --git a/system/stack/Android.bp b/system/stack/Android.bp
index 841e7a93ef..35aa07b616 100644
--- a/system/stack/Android.bp
+++ b/system/stack/Android.bp
@@ -87,7 +87,6 @@ cc_library_static {
"a2dp/a2dp_vendor_aptx_hd.cc",
"a2dp/a2dp_vendor_aptx_hd_encoder.cc",
"a2dp/a2dp_vendor_ldac.cc",
- "a2dp/a2dp_vendor_ldac_decoder.cc",
"a2dp/a2dp_vendor_ldac_encoder.cc",
"a2dp/a2dp_vendor_opus.cc",
"a2dp/a2dp_vendor_opus_decoder.cc",
@@ -495,6 +494,7 @@ cc_fuzz {
"libbluetooth_l2cap_pdl",
"libbluetooth_log",
"libbluetooth_smp_pdl",
+ "libbt-common",
"libbt-platform-protos-lite",
],
}
@@ -567,6 +567,7 @@ cc_fuzz {
":TestCommonMockFunctions",
":TestCommonStackConfig",
":TestFakeOsi",
+ ":TestMockBtaDm",
":TestMockBtif",
":TestMockDevice",
":TestMockMainShim",
@@ -949,6 +950,7 @@ cc_test {
srcs: [
":TestCommonMainHandler",
":TestCommonMockFunctions",
+ ":TestMockBtaDm",
":TestMockBtif",
":TestMockDevice",
":TestMockMainShim",
@@ -1355,7 +1357,6 @@ cc_test {
"a2dp/a2dp_vendor_aptx_hd.cc",
"a2dp/a2dp_vendor_aptx_hd_encoder.cc",
"a2dp/a2dp_vendor_ldac.cc",
- "a2dp/a2dp_vendor_ldac_decoder.cc",
"a2dp/a2dp_vendor_ldac_encoder.cc",
"a2dp/a2dp_vendor_opus.cc",
"a2dp/a2dp_vendor_opus_decoder.cc",
@@ -1412,54 +1413,6 @@ cc_test {
header_libs: ["libbluetooth_headers"],
}
-cc_test {
- name: "net_test_stack_a2dp_native",
- defaults: [
- "fluoride_defaults",
- "mts_defaults",
- ],
- test_suites: ["general-tests"],
- host_supported: true,
- test_options: {
- unit_test: true,
- },
- include_dirs: [
- "external/libldac/inc",
- "packages/modules/Bluetooth/system",
- "packages/modules/Bluetooth/system/gd",
- "packages/modules/Bluetooth/system/stack/include",
- ],
- srcs: [
- "a2dp/a2dp_vendor_ldac_decoder.cc",
- "test/a2dp/a2dp_vendor_ldac_decoder_test.cc",
- "test/a2dp/misc_fake.cc",
- ],
- aidl: {
- libs: ["bluetooth_constants"],
- },
- shared_libs: [
- "libbinder",
- "libcrypto",
- "libcutils",
- ],
- static_libs: [
- "libbase",
- "libbluetooth_crypto_toolbox",
- "libbluetooth_log",
- "libbt-common",
- "libchrome",
- "libcom.android.sysprop.bluetooth.wrapped",
- "liblog",
- "libosi",
- ],
- sanitize: {
- address: true,
- cfi: true,
- misc_undefined: ["bounds"],
- },
- header_libs: ["libbluetooth_headers"],
-}
-
// gatt sr hash test
cc_test {
name: "net_test_stack_gatt_sr_hash_native",
diff --git a/system/stack/a2dp/a2dp_codec_config.cc b/system/stack/a2dp/a2dp_codec_config.cc
index 9155dabf52..47cfc81030 100644
--- a/system/stack/a2dp/a2dp_codec_config.cc
+++ b/system/stack/a2dp/a2dp_codec_config.cc
@@ -192,9 +192,6 @@ A2dpCodecConfig* A2dpCodecConfig::createCodec(btav_a2dp_codec_index_t codec_inde
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
codec_config = new A2dpCodecConfigLdacSource(codec_priority);
break;
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- codec_config = new A2dpCodecConfigLdacSink(codec_priority);
- break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
codec_config = new A2dpCodecConfigOpusSource(codec_priority);
break;
diff --git a/system/stack/a2dp/a2dp_vendor.cc b/system/stack/a2dp/a2dp_vendor.cc
index 28a27c7cb6..febfabb48d 100644
--- a/system/stack/a2dp/a2dp_vendor.cc
+++ b/system/stack/a2dp/a2dp_vendor.cc
@@ -129,11 +129,6 @@ tA2DP_STATUS A2DP_IsVendorSinkCodecSupported(const uint8_t* p_codec_info) {
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
- // Check for LDAC
- if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
- return A2DP_IsVendorSinkCodecSupportedLdac(p_codec_info);
- }
-
// Check for Opus
if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
return A2DP_IsVendorSinkCodecSupportedOpus(p_codec_info);
@@ -279,11 +274,6 @@ int A2DP_VendorGetSinkTrackChannelType(const uint8_t* p_codec_info) {
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
- // Check for LDAC
- if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
- return A2DP_VendorGetSinkTrackChannelTypeLdac(p_codec_info);
- }
-
// Check for Opus
if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
return A2DP_VendorGetSinkTrackChannelTypeOpus(p_codec_info);
@@ -358,11 +348,6 @@ const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterface(const uint8_t* p_c
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
- // Check for LDAC
- if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
- return A2DP_VendorGetDecoderInterfaceLdac(p_codec_info);
- }
-
// Check for Opus
if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
return A2DP_VendorGetDecoderInterfaceOpus(p_codec_info);
@@ -436,11 +421,6 @@ btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndex(const uint8_t* p_codec_info) {
// Add checks based on <vendor_id, codec_id>
// NOTE: Should be done only for local Sink codecs.
- // Check for LDAC
- if (vendor_id == A2DP_LDAC_VENDOR_ID && codec_id == A2DP_LDAC_CODEC_ID) {
- return A2DP_VendorSinkCodecIndexLdac(p_codec_info);
- }
-
// Check for Opus
if (vendor_id == A2DP_OPUS_VENDOR_ID && codec_id == A2DP_OPUS_CODEC_ID) {
return A2DP_VendorSinkCodecIndexOpus(p_codec_info);
@@ -463,8 +443,6 @@ const char* A2DP_VendorCodecIndexStr(btav_a2dp_codec_index_t codec_index) {
return A2DP_VendorCodecIndexStrAptxHd();
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
return A2DP_VendorCodecIndexStrLdac();
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- return A2DP_VendorCodecIndexStrLdacSink();
case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
return "LC3 not implemented";
case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
@@ -496,8 +474,6 @@ bool A2DP_VendorInitCodecConfig(btav_a2dp_codec_index_t codec_index, AvdtpSepCon
return A2DP_VendorInitCodecConfigAptxHd(p_cfg);
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
return A2DP_VendorInitCodecConfigLdac(p_cfg);
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- return A2DP_VendorInitCodecConfigLdacSink(p_cfg);
case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
break; // not implemented
case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
diff --git a/system/stack/a2dp/a2dp_vendor_ldac.cc b/system/stack/a2dp/a2dp_vendor_ldac.cc
index 951be4c35b..ef7fea0be8 100644
--- a/system/stack/a2dp/a2dp_vendor_ldac.cc
+++ b/system/stack/a2dp/a2dp_vendor_ldac.cc
@@ -37,7 +37,6 @@
#include "a2dp_codec_api.h"
#include "a2dp_constants.h"
#include "a2dp_vendor_ldac_constants.h"
-#include "a2dp_vendor_ldac_decoder.h"
#include "a2dp_vendor_ldac_encoder.h"
#include "avdt_api.h"
#include "btif/include/btif_av_co.h"
@@ -102,16 +101,6 @@ static const tA2DP_ENCODER_INTERFACE a2dp_encoder_interface_ldac = {
a2dp_vendor_ldac_send_frames,
a2dp_vendor_ldac_set_transmit_queue_length};
-static const tA2DP_DECODER_INTERFACE a2dp_decoder_interface_ldac = {
- a2dp_vendor_ldac_decoder_init, a2dp_vendor_ldac_decoder_cleanup,
- a2dp_vendor_ldac_decoder_decode_packet, a2dp_vendor_ldac_decoder_start,
- a2dp_vendor_ldac_decoder_suspend, a2dp_vendor_ldac_decoder_configure,
-};
-
-static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityLdac(const tA2DP_LDAC_CIE* p_cap,
- const uint8_t* p_codec_info,
- bool is_peer_codec_info);
-
// Builds the LDAC Media Codec Capabilities byte sequence beginning from the
// LOSC octet. |media_type| is the media type |AVDT_MEDIA_TYPE_*|.
// |p_ie| is a pointer to the LDAC Codec Information Element information.
@@ -250,50 +239,6 @@ bool A2DP_IsCodecValidLdac(const uint8_t* p_codec_info) {
(A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, true) == A2DP_SUCCESS);
}
-tA2DP_STATUS A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info) {
- return A2DP_CodecInfoMatchesCapabilityLdac(&a2dp_ldac_sink_caps, p_codec_info, false);
-}
-
-// Checks whether A2DP LDAC codec configuration matches with a device's codec
-// capabilities. |p_cap| is the LDAC codec configuration. |p_codec_info| is
-// the device's codec capabilities.
-// If |is_capability| is true, the byte sequence is codec capabilities,
-// otherwise is codec configuration.
-// |p_codec_info| contains the codec capabilities for a peer device that
-// is acting as an A2DP source.
-// Returns A2DP_SUCCESS if the codec configuration matches with capabilities,
-// otherwise the corresponding A2DP error status code.
-static tA2DP_STATUS A2DP_CodecInfoMatchesCapabilityLdac(const tA2DP_LDAC_CIE* p_cap,
- const uint8_t* p_codec_info,
- bool is_capability) {
- tA2DP_STATUS status;
- tA2DP_LDAC_CIE cfg_cie;
-
- /* parse configuration */
- status = A2DP_ParseInfoLdac(&cfg_cie, p_codec_info, is_capability);
- if (status != A2DP_SUCCESS) {
- log::error("parsing failed {}", status);
- return status;
- }
-
- /* verify that each parameter is in range */
-
- log::verbose("FREQ peer: 0x{:x}, capability 0x{:x}", cfg_cie.sampleRate, p_cap->sampleRate);
- log::verbose("CH_MODE peer: 0x{:x}, capability 0x{:x}", cfg_cie.channelMode, p_cap->channelMode);
-
- /* sampling frequency */
- if ((cfg_cie.sampleRate & p_cap->sampleRate) == 0) {
- return A2DP_NOT_SUPPORTED_SAMPLING_FREQUENCY;
- }
-
- /* channel mode */
- if ((cfg_cie.channelMode & p_cap->channelMode) == 0) {
- return A2DP_NOT_SUPPORTED_CHANNEL_MODE;
- }
-
- return A2DP_SUCCESS;
-}
-
bool A2DP_VendorUsesRtpHeaderLdac(bool /* content_protection_enabled */,
const uint8_t* /* p_codec_info */) {
// TODO: Is this correct? The RTP header is always included?
@@ -566,15 +511,6 @@ const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(
return &a2dp_encoder_interface_ldac;
}
-const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(
- const uint8_t* p_codec_info) {
- if (!A2DP_IsCodecValidLdac(p_codec_info)) {
- return NULL;
- }
-
- return &a2dp_decoder_interface_ldac;
-}
-
bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info) {
tA2DP_LDAC_CIE cfg_cie;
@@ -590,22 +526,12 @@ btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(const uint8_t* /* p_code
return BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC;
}
-btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac(const uint8_t* /* p_codec_info */) {
- return BTAV_A2DP_CODEC_INDEX_SINK_LDAC;
-}
-
const char* A2DP_VendorCodecIndexStrLdac(void) { return "LDAC"; }
-const char* A2DP_VendorCodecIndexStrLdacSink(void) { return "LDAC SINK"; }
-
bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) {
return A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_source_caps, p_cfg->codec_info);
}
-bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg) {
- return A2DP_BuildInfoLdac(AVDT_MEDIA_TYPE_AUDIO, &a2dp_ldac_sink_caps, p_cfg->codec_info);
-}
-
A2dpCodecConfigLdacSource::A2dpCodecConfigLdacSource(btav_a2dp_codec_priority_t codec_priority)
: A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, A2DP_VendorCodecIndexStrLdac(),
codec_priority, true) {
@@ -1320,24 +1246,3 @@ fail:
sizeof(ota_codec_peer_capability_));
return false;
}
-
-A2dpCodecConfigLdacSink::A2dpCodecConfigLdacSink(btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SINK_LDAC, A2DP_VendorCodecIndexStrLdacSink(),
- codec_priority, false) {}
-
-A2dpCodecConfigLdacSink::~A2dpCodecConfigLdacSink() {}
-
-bool A2dpCodecConfigLdacSink::init() {
- // Load the decoder
- if (!A2DP_VendorLoadDecoderLdac()) {
- log::error("cannot load the decoder");
- return false;
- }
-
- return true;
-}
-
-bool A2dpCodecConfigLdacSink::useRtpHeaderMarkerBit() const {
- // TODO: This method applies only to Source codecs
- return false;
-}
diff --git a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc b/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc
deleted file mode 100644
index 9c13d50160..0000000000
--- a/system/stack/a2dp/a2dp_vendor_ldac_decoder.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-#define LOG_TAG "bluetooth-a2dp"
-
-#include "a2dp_vendor_ldac_decoder.h"
-
-#include <bluetooth/log.h>
-#include <dlfcn.h>
-#include <ldacBT.h>
-#include <ldacBT_bco_for_fluoride.h>
-#include <pthread.h>
-#include <string.h>
-
-#include <cstdint>
-
-#include "a2dp_vendor_ldac.h"
-#include "a2dp_vendor_ldac_constants.h"
-#include "avdt_api.h"
-#include "stack/include/bt_hdr.h"
-
-using namespace bluetooth;
-
-namespace std {
-template <>
-struct formatter<LDACBT_SMPL_FMT_T> : enum_formatter<LDACBT_SMPL_FMT_T> {};
-} // namespace std
-
-//
-// Decoder for LDAC Source Codec
-//
-
-//
-// The LDAC BCO shared library, and the functions to use
-//
-static const char* LDAC_BCO_LIB_NAME = "libldacBT_bco.so";
-static void* ldac_bco_lib_handle = NULL;
-
-static const char* LDAC_BCO_INIT_NAME = "ldac_BCO_init";
-typedef HANDLE_LDAC_BCO (*tLDAC_BCO_INIT)(decoded_data_callback_t decode_callback);
-
-static const char* LDAC_BCO_CLEANUP_NAME = "ldac_BCO_cleanup";
-typedef int32_t (*tLDAC_BCO_CLEANUP)(HANDLE_LDAC_BCO hLdacBco);
-
-static const char* LDAC_BCO_DECODE_PACKET_NAME = "ldac_BCO_decode_packet";
-typedef int32_t (*tLDAC_BCO_DECODE_PACKET)(HANDLE_LDAC_BCO hLdacBco, void* data, int32_t length);
-
-static const char* LDAC_BCO_START_NAME = "ldac_BCO_start";
-typedef int32_t (*tLDAC_BCO_START)(HANDLE_LDAC_BCO hLdacBco);
-
-static const char* LDAC_BCO_SUSPEND_NAME = "ldac_BCO_suspend";
-typedef int32_t (*tLDAC_BCO_SUSPEND)(HANDLE_LDAC_BCO hLdacBco);
-
-static const char* LDAC_BCO_CONFIGURE_NAME = "ldac_BCO_configure";
-typedef int32_t (*tLDAC_BCO_CONFIGURE)(HANDLE_LDAC_BCO hLdacBco, int32_t sample_rate,
- int32_t bits_per_sample, int32_t channel_mode);
-
-static tLDAC_BCO_INIT ldac_BCO_init_func;
-static tLDAC_BCO_CLEANUP ldac_BCO_cleanup_func;
-static tLDAC_BCO_DECODE_PACKET ldac_BCO_decode_packet_func;
-static tLDAC_BCO_START ldac_BCO_start_func;
-static tLDAC_BCO_SUSPEND ldac_BCO_suspend_func;
-static tLDAC_BCO_CONFIGURE ldac_BCO_configure_func;
-
-// offset
-#define A2DP_LDAC_OFFSET (AVDT_MEDIA_OFFSET + A2DP_LDAC_MPL_HDR_LEN)
-
-typedef struct {
- uint32_t sample_rate;
- uint8_t channel_mode;
- uint8_t bits_per_sample;
- int pcm_wlength;
- LDACBT_SMPL_FMT_T pcm_fmt;
-} tA2DP_LDAC_DECODER_PARAMS;
-
-typedef struct {
- pthread_mutex_t mutex;
- bool use_SCMS_T;
- bool is_peer_edr; // True if the peer device supports EDR
- bool peer_supports_3mbps; // True if the peer device supports 3Mbps EDR
- uint16_t peer_mtu; // MTU of the A2DP peer
- uint32_t timestamp; // Timestamp for the A2DP frames
-
- HANDLE_LDAC_BCO ldac_handle_bco;
- bool has_ldac_handle; // True if ldac_handle is valid
- unsigned char* decode_buf;
- decoded_data_callback_t decode_callback;
-} tA2DP_LDAC_DECODER_CB;
-
-static tA2DP_LDAC_DECODER_CB a2dp_ldac_decoder_cb;
-
-static void* load_func(const char* func_name) {
- void* func_ptr = dlsym(ldac_bco_lib_handle, func_name);
- if (func_ptr == NULL) {
- log::error("cannot find function '{}' in the decoder library: {}", func_name, dlerror());
- A2DP_VendorUnloadDecoderLdac();
- return NULL;
- }
- return func_ptr;
-}
-
-bool A2DP_VendorLoadDecoderLdac(void) {
- if (ldac_bco_lib_handle != NULL) {
- return true; // Already loaded
- }
-
- // Initialize the control block
- memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
-
- pthread_mutex_init(&(a2dp_ldac_decoder_cb.mutex), NULL);
-
- // Open the decoder library
- ldac_bco_lib_handle = dlopen(LDAC_BCO_LIB_NAME, RTLD_NOW);
- if (ldac_bco_lib_handle == NULL) {
- log::info("cannot open LDAC decoder library {}: {}", LDAC_BCO_LIB_NAME, dlerror());
- return false;
- }
-
- // Load all functions
- ldac_BCO_init_func = (tLDAC_BCO_INIT)load_func(LDAC_BCO_INIT_NAME);
- if (ldac_BCO_init_func == NULL) {
- return false;
- }
-
- ldac_BCO_cleanup_func = (tLDAC_BCO_CLEANUP)load_func(LDAC_BCO_CLEANUP_NAME);
- if (ldac_BCO_cleanup_func == NULL) {
- return false;
- }
-
- ldac_BCO_decode_packet_func = (tLDAC_BCO_DECODE_PACKET)load_func(LDAC_BCO_DECODE_PACKET_NAME);
- if (ldac_BCO_decode_packet_func == NULL) {
- return false;
- }
-
- ldac_BCO_start_func = (tLDAC_BCO_START)load_func(LDAC_BCO_START_NAME);
- if (ldac_BCO_start_func == NULL) {
- return false;
- }
-
- ldac_BCO_suspend_func = (tLDAC_BCO_SUSPEND)load_func(LDAC_BCO_SUSPEND_NAME);
- if (ldac_BCO_suspend_func == NULL) {
- return false;
- }
-
- ldac_BCO_configure_func = (tLDAC_BCO_CONFIGURE)load_func(LDAC_BCO_CONFIGURE_NAME);
- if (ldac_BCO_configure_func == NULL) {
- return false;
- }
-
- return true;
-}
-
-void A2DP_VendorUnloadDecoderLdac(void) {
- // Cleanup any LDAC-related state
- if (a2dp_ldac_decoder_cb.has_ldac_handle && ldac_BCO_cleanup_func != NULL) {
- ldac_BCO_cleanup_func(a2dp_ldac_decoder_cb.ldac_handle_bco);
- }
- pthread_mutex_destroy(&(a2dp_ldac_decoder_cb.mutex));
- memset(&a2dp_ldac_decoder_cb, 0, sizeof(a2dp_ldac_decoder_cb));
-
- ldac_BCO_init_func = NULL;
- ldac_BCO_cleanup_func = NULL;
- ldac_BCO_decode_packet_func = NULL;
- ldac_BCO_start_func = NULL;
- ldac_BCO_suspend_func = NULL;
- ldac_BCO_configure_func = NULL;
-
- if (ldac_bco_lib_handle != NULL) {
- dlclose(ldac_bco_lib_handle);
- ldac_bco_lib_handle = NULL;
- }
-}
-
-bool a2dp_vendor_ldac_decoder_init(decoded_data_callback_t decode_callback) {
- pthread_mutex_lock(&(a2dp_ldac_decoder_cb.mutex));
-
- if (a2dp_ldac_decoder_cb.has_ldac_handle) {
- ldac_BCO_cleanup_func(a2dp_ldac_decoder_cb.ldac_handle_bco);
- }
-
- a2dp_ldac_decoder_cb.ldac_handle_bco = ldac_BCO_init_func(decode_callback);
- a2dp_ldac_decoder_cb.has_ldac_handle = (a2dp_ldac_decoder_cb.ldac_handle_bco != NULL);
-
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
- return true;
-}
-
-void a2dp_vendor_ldac_decoder_cleanup(void) {
- pthread_mutex_lock(&(a2dp_ldac_decoder_cb.mutex));
- if (a2dp_ldac_decoder_cb.has_ldac_handle) {
- ldac_BCO_cleanup_func(a2dp_ldac_decoder_cb.ldac_handle_bco);
- }
- a2dp_ldac_decoder_cb.ldac_handle_bco = NULL;
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
-}
-
-bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf) {
- if (p_buf == nullptr) {
- log::error("Dropping packet with nullptr");
- return false;
- }
- pthread_mutex_lock(&(a2dp_ldac_decoder_cb.mutex));
- unsigned char* pBuffer = reinterpret_cast<unsigned char*>(p_buf->data + p_buf->offset);
- // unsigned int bufferSize = p_buf->len;
- unsigned int bytesValid = p_buf->len;
- if (bytesValid == 0) {
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
- log::warn("Dropping packet with zero length");
- return false;
- }
-
- int bs_bytes, frame_number;
-
- frame_number = (int)pBuffer[0];
- bs_bytes = (int)bytesValid;
- bytesValid -= 1;
- log::info("INPUT size : {}, frame : {}", bs_bytes, frame_number);
-
- if (a2dp_ldac_decoder_cb.has_ldac_handle) {
- ldac_BCO_decode_packet_func(a2dp_ldac_decoder_cb.ldac_handle_bco, pBuffer, bs_bytes);
- }
-
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
- return true;
-}
-
-void a2dp_vendor_ldac_decoder_start(void) {
- pthread_mutex_lock(&(a2dp_ldac_decoder_cb.mutex));
- log::info("");
- if (a2dp_ldac_decoder_cb.has_ldac_handle) {
- ldac_BCO_start_func(a2dp_ldac_decoder_cb.ldac_handle_bco);
- }
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
-}
-
-void a2dp_vendor_ldac_decoder_suspend(void) {
- pthread_mutex_lock(&(a2dp_ldac_decoder_cb.mutex));
- log::info("");
- if (a2dp_ldac_decoder_cb.has_ldac_handle) {
- ldac_BCO_suspend_func(a2dp_ldac_decoder_cb.ldac_handle_bco);
- }
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
-}
-
-void a2dp_vendor_ldac_decoder_configure(const uint8_t* p_codec_info) {
- int32_t sample_rate;
- int32_t bits_per_sample;
- int32_t channel_mode;
-
- if (p_codec_info == NULL) {
- log::error("p_codec_info is NULL");
- return;
- }
-
- pthread_mutex_lock(&(a2dp_ldac_decoder_cb.mutex));
- sample_rate = A2DP_VendorGetTrackSampleRateLdac(p_codec_info);
- bits_per_sample = A2DP_VendorGetTrackBitsPerSampleLdac(p_codec_info);
- channel_mode = A2DP_VendorGetChannelModeCodeLdac(p_codec_info);
-
- log::info(", sample_rate={}, bits_per_sample={}, channel_mode={}", sample_rate, bits_per_sample,
- channel_mode);
-
- if (a2dp_ldac_decoder_cb.has_ldac_handle) {
- ldac_BCO_configure_func(a2dp_ldac_decoder_cb.ldac_handle_bco, sample_rate, bits_per_sample,
- channel_mode);
- }
- pthread_mutex_unlock(&(a2dp_ldac_decoder_cb.mutex));
-}
diff --git a/system/stack/a2dp/a2dp_vendor_ldac_linux.cc b/system/stack/a2dp/a2dp_vendor_ldac_linux.cc
index a777304c37..2401619c98 100644
--- a/system/stack/a2dp/a2dp_vendor_ldac_linux.cc
+++ b/system/stack/a2dp/a2dp_vendor_ldac_linux.cc
@@ -20,10 +20,6 @@
bool A2DP_IsCodecValidLdac(const uint8_t* p_codec_info) { return false; }
-tA2DP_STATUS A2DP_IsVendorSinkCodecSupportedLdac(const uint8_t* p_codec_info) {
- return A2DP_NOT_SUPPORTED_CODEC_TYPE;
-}
-
bool A2DP_VendorUsesRtpHeaderLdac(bool content_protection_enabled,
const uint8_t* p_codec_info) {
return false;
@@ -51,8 +47,6 @@ int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* p_codec_info) { return -
int A2DP_VendorGetTrackChannelCountLdac(const uint8_t* p_codec_info) { return -1; }
-int A2DP_VendorGetSinkTrackChannelTypeLdac(const uint8_t* p_codec_info) { return -1; }
-
int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* p_codec_info) { return -1; }
int A2DP_VendorGetFrameSizeLdac(const uint8_t* p_codec_info) { return -1; }
@@ -75,28 +69,16 @@ const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(const uint8_t*
return nullptr;
}
-const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(const uint8_t* p_codec_info) {
- return nullptr;
-}
-
bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info) { return false; }
btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(const uint8_t* p_codec_info) {
return BTAV_A2DP_CODEC_INDEX_MAX;
}
-btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac(const uint8_t* p_codec_info) {
- return BTAV_A2DP_CODEC_INDEX_MAX;
-}
-
const char* A2DP_VendorCodecIndexStrLdac(void) { return "Ldac"; }
-const char* A2DP_VendorCodecIndexStrLdacSink(void) { return "Ldac SINK"; }
-
bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg) { return false; }
-bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg) { return false; }
-
A2dpCodecConfigLdacSource::A2dpCodecConfigLdacSource(btav_a2dp_codec_priority_t codec_priority)
: A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC, A2DP_VendorCodecIndexStrLdac(),
codec_priority, true) {}
@@ -118,13 +100,3 @@ tA2DP_STATUS A2dpCodecConfigLdacBase::setCodecConfig(const uint8_t* p_peer_codec
bool A2dpCodecConfigLdacBase::setPeerCodecCapabilities(const uint8_t* p_peer_codec_capabilities) {
return false;
}
-
-A2dpCodecConfigLdacSink::A2dpCodecConfigLdacSink(btav_a2dp_codec_priority_t codec_priority)
- : A2dpCodecConfigLdacBase(BTAV_A2DP_CODEC_INDEX_SINK_LDAC, A2DP_VendorCodecIndexStrLdacSink(),
- codec_priority, false) {}
-
-A2dpCodecConfigLdacSink::~A2dpCodecConfigLdacSink() {}
-
-bool A2dpCodecConfigLdacSink::init() { return false; }
-
-bool A2dpCodecConfigLdacSink::useRtpHeaderMarkerBit() const { return false; }
diff --git a/system/stack/acl/ble_acl.cc b/system/stack/acl/ble_acl.cc
index 0aeb9ceb91..ab439987ed 100644
--- a/system/stack/acl/ble_acl.cc
+++ b/system/stack/acl/ble_acl.cc
@@ -38,8 +38,6 @@ using namespace bluetooth;
extern tBTM_CB btm_cb;
-void btm_ble_increment_link_topology_mask(uint8_t link_role);
-
static bool acl_ble_common_connection(const tBLE_BD_ADDR& address_with_type, uint16_t handle,
tHCI_ROLE role, bool is_in_security_db,
uint16_t conn_interval, uint16_t conn_latency,
diff --git a/system/stack/acl/btm_acl.cc b/system/stack/acl/btm_acl.cc
index 16911e9cc5..2a55ee393d 100644
--- a/system/stack/acl/btm_acl.cc
+++ b/system/stack/acl/btm_acl.cc
@@ -61,6 +61,7 @@
#include "stack/btm/btm_int_types.h"
#include "stack/btm/btm_sco.h"
#include "stack/btm/btm_sec.h"
+#include "stack/btm/internal/btm_api.h"
#include "stack/btm/security_device_record.h"
#include "stack/include/acl_api.h"
#include "stack/include/acl_api_types.h"
@@ -69,6 +70,7 @@
#include "stack/include/bt_types.h"
#include "stack/include/btm_ble_api.h"
#include "stack/include/btm_client_interface.h"
+#include "stack/include/btm_iot_config.h"
#include "stack/include/btm_iso_api.h"
#include "stack/include/btm_status.h"
#include "stack/include/hci_error_code.h"
@@ -92,14 +94,7 @@
using namespace bluetooth;
using bluetooth::legacy::hci::GetInterface;
-void BTM_update_version_info(const RawAddress& bd_addr,
- const remote_version_info& remote_version_info);
-
-void BTM_db_reset(void);
-
extern tBTM_CB btm_cb;
-void btm_iot_save_remote_properties(tACL_CONN* p_acl_cb);
-void btm_iot_save_remote_versions(tACL_CONN* p_acl_cb);
struct StackAclBtmAcl {
tACL_CONN* acl_allocate_connection();
@@ -157,8 +152,8 @@ static void btm_read_failed_contact_counter_timeout(void* data);
static void btm_read_remote_ext_features(uint16_t handle, uint8_t page_number);
static void btm_read_rssi_timeout(void* data);
static void btm_read_tx_power_timeout(void* data);
+static void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy);
static void check_link_policy(tLINK_POLICY* settings);
-void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy);
namespace {
void NotifyAclLinkUp(tACL_CONN& p_acl) {
@@ -669,7 +664,7 @@ static void check_link_policy(tLINK_POLICY* settings) {
}
}
-void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy) {
+static void btm_set_link_policy(tACL_CONN* conn, tLINK_POLICY policy) {
conn->link_policy = policy;
check_link_policy(&conn->link_policy);
if ((conn->link_policy & HCI_ENABLE_CENTRAL_PERIPHERAL_SWITCH) &&
diff --git a/system/stack/avrc/avrc_api.cc b/system/stack/avrc/avrc_api.cc
index 13184ed058..6b3c1700cb 100644
--- a/system/stack/avrc/avrc_api.cc
+++ b/system/stack/avrc/avrc_api.cc
@@ -25,6 +25,7 @@
#include <android_bluetooth_sysprop.h>
#include <bluetooth/log.h>
+#include <com_android_bluetooth_flags.h>
#include <string.h>
#include <cstdint>
@@ -1009,7 +1010,12 @@ uint16_t AVRC_GetControlProfileVersion() {
uint16_t AVRC_GetProfileVersion() {
uint16_t profile_version = AVRC_REV_1_4;
char avrcp_version[PROPERTY_VALUE_MAX] = {0};
- osi_property_get(AVRC_VERSION_PROPERTY, avrcp_version, AVRC_DEFAULT_VERSION);
+
+ if (!com::android::bluetooth::flags::avrcp_16_default()) {
+ osi_property_get(AVRC_VERSION_PROPERTY, avrcp_version, AVRC_1_5_STRING);
+ } else {
+ osi_property_get(AVRC_VERSION_PROPERTY, avrcp_version, AVRC_1_6_STRING);
+ }
if (!strncmp(AVRC_1_6_STRING, avrcp_version, sizeof(AVRC_1_6_STRING))) {
profile_version = AVRC_REV_1_6;
diff --git a/system/stack/btm/btm_ble.cc b/system/stack/btm/btm_ble.cc
index e71dfe67fa..b612b684b3 100644
--- a/system/stack/btm/btm_ble.cc
+++ b/system/stack/btm/btm_ble.cc
@@ -35,6 +35,7 @@
#include "stack/btm/btm_int_types.h"
#include "stack/gatt/gatt_int.h"
#include "stack/include/acl_api.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_ble_api.h"
#include "stack/include/btm_client_interface.h"
@@ -42,9 +43,6 @@
#include "stack/include/gatt_api.h"
#include "stack/include/hcimsgs.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
extern tBTM_CB btm_cb;
@@ -136,8 +134,8 @@ bool BTM_UseLeLink(const RawAddress& bd_addr) {
return dev_type == BT_DEVICE_TYPE_BLE;
}
-void read_phy_cb(base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
- uint8_t* data, uint16_t len) {
+static void read_phy_cb(base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
+ uint8_t* data, uint16_t len) {
uint8_t status, tx_phy, rx_phy;
uint16_t handle;
@@ -188,8 +186,6 @@ void BTM_BleReadPhy(const RawAddress& bd_addr,
base::Bind(&read_phy_cb, std::move(cb)));
}
-void doNothing(uint8_t* /* data */, uint16_t /* len */) {}
-
void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
uint16_t phy_options) {
if (!get_btm_client_interface().peer.BTM_IsAclConnectionUp(bd_addr, BT_TRANSPORT_LE)) {
@@ -233,5 +229,6 @@ void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
UINT8_TO_STREAM(pp, tx_phys);
UINT8_TO_STREAM(pp, rx_phys);
UINT16_TO_STREAM(pp, phy_options);
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_SET_PHY, data, len, base::Bind(doNothing));
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_SET_PHY, data, len,
+ base::Bind([](uint8_t*, uint16_t) {}));
}
diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc
index 462a93e394..808c9491d1 100644
--- a/system/stack/btm/btm_ble_gap.cc
+++ b/system/stack/btm/btm_ble_gap.cc
@@ -71,15 +71,10 @@
#include "types/ble_address_with_type.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
extern tBTM_CB btm_cb;
-void btm_ble_adv_filter_init(void);
-
#define BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS (30 * 1000)
#define MIN_ADV_LENGTH 2
#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN 9
@@ -197,7 +192,7 @@ AdvertisingCache cache;
} // namespace
-bool ble_vnd_is_included() {
+static bool ble_vnd_is_included() {
// replace build time config BLE_VND_INCLUDED with runtime
return android::sysprop::bluetooth::Ble::vnd_included().value_or(true);
}
@@ -278,11 +273,6 @@ static void btm_ble_start_sync_timeout(void* data);
* Local functions
******************************************************************************/
static void btm_ble_update_adv_flag(uint8_t flag);
-void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type,
- const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy,
- uint8_t advertising_sid, int8_t tx_power, int8_t rssi,
- uint16_t periodic_adv_int, uint8_t data_len, const uint8_t* data,
- const RawAddress& original_bda);
static uint8_t btm_set_conn_mode_adv_init_addr(RawAddress& p_peer_addr_ptr,
tBLE_ADDR_TYPE* p_peer_addr_type,
tBLE_ADDR_TYPE* p_own_addr_type);
@@ -488,7 +478,7 @@ void BTM_BleTargetAnnouncementObserve(bool enable, tBTM_INQ_RESULTS_CB* p_result
}
}
-std::pair<uint16_t /* interval */, uint16_t /* window */> get_low_latency_scan_params() {
+static std::pair<uint16_t /* interval */, uint16_t /* window */> get_low_latency_scan_params() {
uint16_t scan_interval =
osi_property_get_int32(kPropertyInquiryScanInterval, BTM_BLE_LOW_LATENCY_SCAN_INT);
uint16_t scan_window =
@@ -862,7 +852,8 @@ static void sync_queue_cleanup(remove_sync_node_t* p_param) {
}
}
-void btm_ble_start_sync_request(uint8_t sid, RawAddress addr, uint16_t skip, uint16_t timeout) {
+static void btm_ble_start_sync_request(uint8_t sid, RawAddress addr, uint16_t skip,
+ uint16_t timeout) {
tBLE_ADDR_TYPE address_type = BLE_ADDR_RANDOM;
tINQ_DB_ENT* p_i = btm_inq_db_find(addr);
if (p_i) {
@@ -1235,8 +1226,8 @@ static void btm_ble_select_adv_interval(uint8_t evt_type, uint16_t* p_adv_int_mi
* Returns void
*
******************************************************************************/
-void btm_ble_update_dmt_flag_bits(uint8_t* adv_flag_value, const uint16_t connect_mode,
- const uint16_t disc_mode) {
+static void btm_ble_update_dmt_flag_bits(uint8_t* adv_flag_value, const uint16_t connect_mode,
+ const uint16_t disc_mode) {
/* BR/EDR non-discoverable , non-connectable */
if ((disc_mode & BTM_DISCOVERABLE_MASK) == 0 && (connect_mode & BTM_CONNECTABLE_MASK) == 0) {
*adv_flag_value |= BTM_BLE_BREDR_NOT_SPT;
@@ -1265,7 +1256,7 @@ void btm_ble_update_dmt_flag_bits(uint8_t* adv_flag_value, const uint16_t connec
* Returns void
*
******************************************************************************/
-void btm_ble_set_adv_flag(uint16_t connect_mode, uint16_t disc_mode) {
+static void btm_ble_set_adv_flag(uint16_t connect_mode, uint16_t disc_mode) {
uint8_t flag = 0, old_flag = 0;
tBTM_BLE_LOCAL_ADV_DATA* p_adv_data = &btm_cb.ble_ctr_cb.inq_var.adv_data;
@@ -1594,8 +1585,8 @@ tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) {
* Returns void
*
******************************************************************************/
-void btm_ble_read_remote_name_cmpl(bool status, const RawAddress& bda, uint16_t length,
- char* p_name) {
+static void btm_ble_read_remote_name_cmpl(bool status, const RawAddress& bda, uint16_t length,
+ char* p_name) {
tHCI_STATUS hci_status = HCI_SUCCESS;
BD_NAME bd_name;
bd_name_from_char_pointer(bd_name, p_name);
@@ -1918,7 +1909,7 @@ static DEV_CLASS btm_ble_appearance_to_cod(uint16_t appearance) {
dev_class[1] = BTM_COD_MAJOR_PERIPHERAL;
dev_class[2] = BTM_COD_MINOR_DIGITAL_PAN;
break;
- case BTM_BLE_APPEARANCE_UKNOWN:
+ case BTM_BLE_APPEARANCE_UNKNOWN:
case BTM_BLE_APPEARANCE_GENERIC_CLOCK:
case BTM_BLE_APPEARANCE_GENERIC_TAG:
case BTM_BLE_APPEARANCE_GENERIC_KEYRING:
diff --git a/system/stack/btm/btm_ble_int.h b/system/stack/btm/btm_ble_int.h
index eb8e88a2ce..bc2b4a896b 100644
--- a/system/stack/btm/btm_ble_int.h
+++ b/system/stack/btm/btm_ble_int.h
@@ -23,11 +23,11 @@
*
******************************************************************************/
-#ifndef BTM_BLE_INT_H
-#define BTM_BLE_INT_H
+#pragma once
#include "stack/btm/btm_ble_int_types.h"
#include "stack/btm/security_device_record.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/hci_error_code.h"
#include "types/ble_address_with_type.h"
#include "types/raw_address.h"
@@ -53,8 +53,10 @@ void btm_ble_adv_filter_init(void);
bool btm_ble_topology_check(tBTM_BLE_STATE_MASK request);
bool btm_ble_clear_topology_mask(tBTM_BLE_STATE_MASK request_state);
bool btm_ble_set_topology_mask(tBTM_BLE_STATE_MASK request_state);
+tBTM_STATUS btm_ble_start_inquiry(uint8_t duration);
+void btm_ble_stop_inquiry(void);
+tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode);
+tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode);
void btm_ble_scanner_init(void);
void btm_ble_scanner_cleanup(void);
-
-#endif
diff --git a/system/stack/btm/btm_ble_privacy.cc b/system/stack/btm/btm_ble_privacy.cc
index bba53e0448..c0b83336b5 100644
--- a/system/stack/btm/btm_ble_privacy.cc
+++ b/system/stack/btm/btm_ble_privacy.cc
@@ -35,14 +35,12 @@
#include "main/shim/entry.h"
#include "osi/include/allocator.h"
#include "stack/btm/btm_int_types.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/bt_octets.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_client_interface.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
extern tBTM_CB btm_cb;
diff --git a/system/stack/btm/btm_ble_sec.cc b/system/stack/btm/btm_ble_sec.cc
index e05091f656..9d6a604ee7 100644
--- a/system/stack/btm/btm_ble_sec.cc
+++ b/system/stack/btm/btm_ble_sec.cc
@@ -44,6 +44,7 @@
#include "stack/btm/security_device_record.h"
#include "stack/eatt/eatt.h"
#include "stack/include/acl_api.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/bt_name.h"
#include "stack/include/bt_octets.h"
#include "stack/include/bt_types.h"
@@ -52,6 +53,7 @@
#include "stack/include/btm_ble_sec_api.h"
#include "stack/include/btm_client_interface.h"
#include "stack/include/btm_log_history.h"
+#include "stack/include/btm_sec_api.h"
#include "stack/include/btm_status.h"
#include "stack/include/gatt_api.h"
#include "stack/include/l2cap_security_interface.h"
@@ -59,17 +61,10 @@
#include "stack/include/smp_api_types.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
extern tBTM_CB btm_cb;
-bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr);
-tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb);
-tBTM_STATUS btm_ble_read_remote_cod(const RawAddress& remote_bda);
-
namespace {
constexpr char kBtmLogTag[] = "SEC";
}
diff --git a/system/stack/btm/btm_dev.cc b/system/stack/btm/btm_dev.cc
index 4840a6d36e..b7275d00d7 100644
--- a/system/stack/btm/btm_dev.cc
+++ b/system/stack/btm/btm_dev.cc
@@ -49,9 +49,6 @@
#include "stack/include/l2cap_interface.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
extern tBTM_CB btm_cb;
@@ -825,11 +822,11 @@ void DumpsysRecord(int fd) {
#undef DUMPSYS_TAG
namespace bluetooth {
-namespace testing {
namespace legacy {
+namespace testing {
void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec) { ::wipe_secrets_and_remove(p_dev_rec); }
-} // namespace legacy
} // namespace testing
+} // namespace legacy
} // namespace bluetooth
diff --git a/system/stack/btm/btm_dev.h b/system/stack/btm/btm_dev.h
index ca9a38ad57..463a84c104 100644
--- a/system/stack/btm/btm_dev.h
+++ b/system/stack/btm/btm_dev.h
@@ -215,3 +215,7 @@ const tBLE_BD_ADDR BTM_Sec_GetAddressWithType(const RawAddress& bd_addr);
*
******************************************************************************/
void DumpsysRecord(int fd);
+
+namespace bluetooth::legacy::testing {
+void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec);
+} // namespace bluetooth::legacy::testing
diff --git a/system/stack/btm/btm_devctl.cc b/system/stack/btm/btm_devctl.cc
index 953487b183..834834f61c 100644
--- a/system/stack/btm/btm_devctl.cc
+++ b/system/stack/btm/btm_devctl.cc
@@ -38,6 +38,7 @@
#include "main/shim/entry.h"
#include "stack/btm/btm_int_types.h"
#include "stack/btm/btm_sec.h"
+#include "stack/btm/internal/btm_api.h"
#include "stack/connection_manager/connection_manager.h"
#include "stack/include/acl_api.h"
#include "stack/include/acl_api_types.h"
@@ -45,19 +46,17 @@
#include "stack/include/bt_types.h"
#include "stack/include/btm_ble_privacy.h"
#include "stack/include/btm_inq.h"
+#include "stack/include/btm_sec_api.h"
#include "stack/include/btm_status.h"
+#include "stack/include/dev_hci_link_interface.h"
#include "stack/include/hcidefs.h"
#include "stack/include/l2cap_controller_interface.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace ::bluetooth;
extern tBTM_CB btm_cb;
-void btm_inq_db_reset(void);
/******************************************************************************/
/* L O C A L D A T A D E F I N I T I O N S */
/******************************************************************************/
@@ -81,34 +80,6 @@ static void decode_controller_support();
/*******************************************************************************
*
- * Function btm_dev_init
- *
- * Description This function is on the BTM startup
- *
- * Returns void
- *
- ******************************************************************************/
-void btm_dev_init() {
- /* Initialize nonzero defaults */
- memset(btm_sec_cb.cfg.bd_name, 0, sizeof(BD_NAME));
-
- btm_cb.devcb.read_rssi_timer = alarm_new("btm.read_rssi_timer");
- btm_cb.devcb.read_failed_contact_counter_timer =
- alarm_new("btm.read_failed_contact_counter_timer");
- btm_cb.devcb.read_automatic_flush_timeout_timer =
- alarm_new("btm.read_automatic_flush_timeout_timer");
- btm_cb.devcb.read_tx_power_timer = alarm_new("btm.read_tx_power_timer");
-}
-
-void btm_dev_free() {
- alarm_free(btm_cb.devcb.read_rssi_timer);
- alarm_free(btm_cb.devcb.read_failed_contact_counter_timer);
- alarm_free(btm_cb.devcb.read_automatic_flush_timeout_timer);
- alarm_free(btm_cb.devcb.read_tx_power_timer);
-}
-
-/*******************************************************************************
- *
* Function btm_db_reset
*
* Returns void
diff --git a/system/stack/btm/btm_inq.cc b/system/stack/btm/btm_inq.cc
index b1ed1c6d03..f478aff768 100644
--- a/system/stack/btm/btm_inq.cc
+++ b/system/stack/btm/btm_inq.cc
@@ -48,6 +48,7 @@
#include "osi/include/properties.h"
#include "osi/include/stack_power_telemetry.h"
#include "packet/bit_inserter.h"
+#include "stack/btm/btm_ble_int.h"
#include "stack/btm/btm_eir.h"
#include "stack/btm/btm_int_types.h"
#include "stack/btm/neighbor_inquiry.h"
@@ -85,9 +86,6 @@
((uint32_t)1 << (((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))) >> \
(((uint32_t)(service)) % BTM_EIR_ARRAY_BITS))
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
namespace {
constexpr char kBtmLogTag[] = "SCAN";
@@ -118,12 +116,6 @@ uint16_t max_bd_entries_; /* Maximum number of entries that can be stored */
} // namespace
extern tBTM_CB btm_cb;
-void btm_inq_db_set_inq_by_rssi(void);
-tBTM_STATUS btm_ble_set_discoverability(uint16_t combined_mode);
-tBTM_STATUS btm_ble_set_connectability(uint16_t combined_mode);
-
-tBTM_STATUS btm_ble_start_inquiry(uint8_t duration);
-void btm_ble_stop_inquiry(void);
using namespace bluetooth;
using bluetooth::Uuid;
@@ -241,16 +233,15 @@ const uint16_t BTM_EIR_UUID_LKUP_TBL[BTM_EIR_MAX_SERVICES] = {
/******************************************************************************/
static void btm_clr_inq_db(const RawAddress* p_bda);
static void btm_init_inq_result_flt(void);
-void btm_clr_inq_result_flt(void);
static uint8_t btm_convert_uuid_to_eir_service(uint16_t uuid16);
-void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results);
static const uint8_t* btm_eir_get_uuid_list(const uint8_t* p_eir, size_t eir_len, uint8_t uuid_size,
uint8_t* p_num_uuid, uint8_t* p_uuid_list_type);
-
+static void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results);
static void btm_process_cancel_complete(tHCI_STATUS status, uint8_t mode);
static void on_incoming_hci_event(EventView event);
static bool is_inquery_by_rssi() { return osi_property_get_bool(PROPERTY_INQ_BY_RSSI, false); }
+
/*******************************************************************************
*
* Function BTM_SetDiscoverability
@@ -889,7 +880,7 @@ tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda) {
* Returns void
*
******************************************************************************/
-void btm_clear_all_pending_le_entry(void) {
+static void btm_clear_all_pending_le_entry(void) {
uint16_t xx;
std::lock_guard<std::mutex> lock(inq_db_lock_);
tINQ_DB_ENT* p_ent = inq_db_;
@@ -989,11 +980,11 @@ void btm_inq_db_reset(void) {
* Returns void
*
******************************************************************************/
-void btm_clr_inq_db(const RawAddress* p_bda) {
+static void btm_clr_inq_db(const RawAddress* p_bda) {
uint16_t xx;
#if (BTM_INQ_DEBUG == TRUE)
- log::verbose("btm_clr_inq_db: inq_active:0x{:x} state:{}", btm_cb.btm_inq_vars.inq_active,
+ log::verbose("inq_active:0x{:x} state:{}", btm_cb.btm_inq_vars.inq_active,
btm_cb.btm_inq_vars.state);
#endif
std::lock_guard<std::mutex> lock(inq_db_lock_);
@@ -1600,7 +1591,7 @@ static void btm_process_inq_results_extended(EventView event) {
* Returns void
*
******************************************************************************/
-void btm_sort_inq_result(void) {
+static void btm_sort_inq_result(void) {
uint8_t xx, yy, num_resp;
std::lock_guard<std::mutex> lock(inq_db_lock_);
tINQ_DB_ENT* p_ent = inq_db_;
@@ -2073,7 +2064,7 @@ static uint16_t btm_convert_uuid_to_uuid16(const uint8_t* p_uuid, uint8_t uuid_s
* Returns None
*
******************************************************************************/
-void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) {
+static void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) {
const uint8_t* p_uuid_data;
uint8_t num_uuid;
uint16_t uuid16;
@@ -2192,12 +2183,3 @@ void tBTM_INQUIRY_VAR_ST::Init() {
}
void tBTM_INQUIRY_VAR_ST::Free() { alarm_free(classic_inquiry_timer); }
-
-namespace bluetooth {
-namespace legacy {
-namespace testing {
-void btm_clr_inq_db(const RawAddress* p_bda) { ::btm_clr_inq_db(p_bda); }
-uint16_t btm_get_num_bd_entries() { return num_bd_entries_; }
-} // namespace testing
-} // namespace legacy
-} // namespace bluetooth
diff --git a/system/stack/btm/btm_iot_config.cc b/system/stack/btm/btm_iot_config.cc
index 27990d3e86..56d6c90ef9 100644
--- a/system/stack/btm/btm_iot_config.cc
+++ b/system/stack/btm/btm_iot_config.cc
@@ -18,6 +18,8 @@
#define LOG_TAG "btm_iot"
+#include "stack/include/btm_iot_config.h"
+
#include <bluetooth/log.h>
#include "btif/include/btif_storage.h"
@@ -26,9 +28,6 @@
#include "stack/acl/acl.h"
#include "stack/include/btm_client_interface.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
/*******************************************************************************
diff --git a/system/stack/btm/btm_main.cc b/system/stack/btm/btm_main.cc
index 581b4d6445..8cf5328ad6 100644
--- a/system/stack/btm/btm_main.cc
+++ b/system/stack/btm/btm_main.cc
@@ -30,12 +30,12 @@
#include "common/strings.h"
#include "main/shim/dumpsys.h"
#include "stack/btm/btm_int_types.h"
+#include "stack/btm/internal/btm_api.h"
+#include "stack/include/btm_client_interface.h"
+#include "stack/include/btm_log_history.h"
#include "stack/include/security_client_callbacks.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
using namespace bluetooth;
/* Global BTM control block structure
diff --git a/system/stack/btm/btm_sco.cc b/system/stack/btm/btm_sco.cc
index ecb0c4d734..c48b321448 100644
--- a/system/stack/btm/btm_sco.cc
+++ b/system/stack/btm/btm_sco.cc
@@ -58,13 +58,11 @@
#include "stack/include/hci_error_code.h"
#include "stack/include/hcimsgs.h"
#include "stack/include/main_thread.h"
+#include "stack/include/sco_hci_link_interface.h"
#include "stack/include/sdpdefs.h"
#include "stack/include/stack_metrics_logging.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
extern tBTM_CB btm_cb;
/* Default to allow enhanced connections where supported. */
@@ -92,11 +90,15 @@ constexpr char kBtmLogTag[] = "SCO";
using namespace bluetooth;
using bluetooth::legacy::hci::GetInterface;
-// forward declaration for dequeueing packets
+/******************************************************************************/
+/* L O C A L F U N C T I O N P R O T O T Y P E S */
+/******************************************************************************/
+static tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx, tBTM_CHG_ESCO_PARAMS* p_parms);
+
+static void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason);
+static uint16_t btm_sco_voice_settings_to_legacy(enh_esco_params_t* p_parms);
static void btm_route_sco_data(bluetooth::hci::ScoView valid_packet);
-void btm_sco_conn_req(const RawAddress& bda, const DEV_CLASS& dev_class, uint8_t link_type);
-void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason);
-bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason);
+static bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason);
namespace cpp {
bluetooth::common::BidiQueueEnd<bluetooth::hci::ScoBuilder, bluetooth::hci::ScoView>*
@@ -214,7 +216,7 @@ enum btm_pcm_buf_state {
DECODE_BUF_PARTIAL,
};
-void incr_btm_pcm_buf_offset(size_t& offset, bool& mirror, size_t amount) {
+static void incr_btm_pcm_buf_offset(size_t& offset, bool& mirror, size_t amount) {
size_t bytes_remaining = BTM_SCO_DATA_SIZE_MAX - offset;
if (bytes_remaining > amount) {
offset += amount;
@@ -225,7 +227,7 @@ void incr_btm_pcm_buf_offset(size_t& offset, bool& mirror, size_t amount) {
offset = amount - bytes_remaining;
}
-btm_pcm_buf_state btm_pcm_buf_status() {
+static btm_pcm_buf_state btm_pcm_buf_status() {
if (btm_pcm_buf_read_offset == btm_pcm_buf_write_offset) {
if (btm_pcm_buf_read_mirror == btm_pcm_buf_write_mirror) {
return DECODE_BUF_EMPTY;
@@ -235,7 +237,7 @@ btm_pcm_buf_state btm_pcm_buf_status() {
return DECODE_BUF_PARTIAL;
}
-size_t btm_pcm_buf_data_len() {
+static size_t btm_pcm_buf_data_len() {
switch (btm_pcm_buf_status()) {
case DECODE_BUF_EMPTY:
return 0;
@@ -250,9 +252,9 @@ size_t btm_pcm_buf_data_len() {
};
}
-size_t btm_pcm_buf_avail_len() { return BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_data_len(); }
+static size_t btm_pcm_buf_avail_len() { return BTM_SCO_DATA_SIZE_MAX - btm_pcm_buf_data_len(); }
-size_t write_btm_pcm_buf(uint8_t* source, size_t amount) {
+static size_t write_btm_pcm_buf(uint8_t* source, size_t amount) {
if (btm_pcm_buf_avail_len() < amount) {
return 0;
}
@@ -269,13 +271,6 @@ size_t write_btm_pcm_buf(uint8_t* source, size_t amount) {
return amount;
}
-/******************************************************************************/
-/* L O C A L F U N C T I O N P R O T O T Y P E S */
-/******************************************************************************/
-static tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx, tBTM_CHG_ESCO_PARAMS* p_parms);
-
-static uint16_t btm_sco_voice_settings_to_legacy(enh_esco_params_t* p_parms);
-
/*******************************************************************************
*
* Function btm_esco_conn_rsp
@@ -1226,7 +1221,7 @@ void BTM_RemoveScoByBdaddr(const RawAddress& bda) {
* Returns true if the link is known about, else false
*
******************************************************************************/
-bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) {
+static bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) {
tSCO_CONN* p = &btm_cb.sco_cb.sco_db[0];
uint16_t xx;
@@ -1255,7 +1250,7 @@ bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason) {
return false;
}
-void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) {
+static void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason) {
tSCO_CONN* p_sco = btm_cb.sco_cb.get_sco_connection_from_handle(hci_handle);
if (p_sco == nullptr) {
log::debug("Unable to find sco connection");
diff --git a/system/stack/btm/btm_sco.h b/system/stack/btm/btm_sco.h
index eea4ebe94a..ab55e78e44 100644
--- a/system/stack/btm/btm_sco.h
+++ b/system/stack/btm/btm_sco.h
@@ -302,3 +302,4 @@ void btm_send_sco_packet(std::vector<uint8_t> data);
bool btm_peer_supports_esco_2m_phy(RawAddress remote_bda);
bool btm_peer_supports_esco_3m_phy(RawAddress remote_bda);
bool btm_peer_supports_esco_ev3(RawAddress remote_bda);
+void btm_sco_acl_removed(const RawAddress* bda);
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 63be75bffd..149791017a 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -79,13 +79,8 @@
#include "types/bt_transport.h"
#include "types/raw_address.h"
-// TODO(b/369381361) Enfore -Wmissing-prototypes
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-
namespace {
-
constexpr char kBtmLogTag[] = "SEC";
-
}
using namespace bluetooth;
@@ -103,9 +98,6 @@ extern tBTM_CB btm_cb;
(BTM_SEC_LE_AUTHENTICATED | BTM_SEC_LE_ENCRYPTED | BTM_SEC_LE_LINK_KEY_KNOWN | \
BTM_SEC_LE_LINK_KEY_AUTHED)
-bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec, const RawAddress& new_pseudo_addr);
-void bta_dm_remove_device(const RawAddress& bd_addr);
-
static tBTM_STATUS btm_sec_execute_procedure(tBTM_SEC_DEV_REC* p_dev_rec);
static bool btm_sec_start_get_name(tBTM_SEC_DEV_REC* p_dev_rec);
static void btm_sec_wait_and_start_authentication(tBTM_SEC_DEV_REC* p_dev_rec);
@@ -177,12 +169,6 @@ static bool handleUnexpectedEncryptionChange() {
return sHandleUnexpectedEncryptionChange;
}
-void NotifyBondingCanceled(tBTM_STATUS /* btm_status */) {
- if (btm_sec_cb.api.p_bond_cancel_cmpl_callback) {
- btm_sec_cb.api.p_bond_cancel_cmpl_callback(tBTM_STATUS::BTM_SUCCESS);
- }
-}
-
/*******************************************************************************
*
* Function btm_dev_authenticated
@@ -2142,9 +2128,9 @@ static void call_registered_rmt_name_callbacks(const RawAddress* p_bd_addr,
* nullptr if record is not found
*
******************************************************************************/
-tBTM_SEC_DEV_REC* btm_rnr_add_name_to_security_record(const RawAddress* p_bd_addr,
- const uint8_t* p_bd_name,
- tHCI_STATUS hci_status) {
+static tBTM_SEC_DEV_REC* btm_rnr_add_name_to_security_record(const RawAddress* p_bd_addr,
+ const uint8_t* p_bd_name,
+ tHCI_STATUS hci_status) {
/* If remote name request failed, p_bd_addr is null and we need to search */
/* based on state assuming that we are doing 1 at a time */
tBTM_SEC_DEV_REC* p_dev_rec = nullptr;
diff --git a/system/stack/btm/btm_sec.h b/system/stack/btm/btm_sec.h
index 117edc0c3c..ade49b883e 100644
--- a/system/stack/btm/btm_sec.h
+++ b/system/stack/btm/btm_sec.h
@@ -60,6 +60,8 @@ bool BTM_IsLinkKeyAuthed(const RawAddress& bd_addr, tBT_TRANSPORT transport);
bool BTM_IsLinkKeyKnown(const RawAddress& bd_addr, tBT_TRANSPORT transport);
bool BTM_IsAuthenticated(const RawAddress& bd_addr, tBT_TRANSPORT transport);
bool BTM_CanReadDiscoverableCharacteristics(const RawAddress& bd_addr);
+void BTM_update_version_info(const RawAddress& bd_addr,
+ const remote_version_info& remote_version_info);
/*******************************************************************************
*
@@ -401,7 +403,7 @@ void btm_sec_conn_req(const RawAddress& bda, const DEV_CLASS dc);
* Returns void
*
******************************************************************************/
-void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr, uint32_t value);
+void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr);
/*******************************************************************************
*
diff --git a/system/stack/btm/internal/btm_api.h b/system/stack/btm/internal/btm_api.h
index 88960be4fd..21df1fe46c 100644
--- a/system/stack/btm/internal/btm_api.h
+++ b/system/stack/btm/internal/btm_api.h
@@ -49,6 +49,7 @@ void btm_free();
* DEVICE CONTROL and COMMON FUNCTIONS
****************************************************************************/
+void BTM_db_reset(void);
void BTM_reset_complete();
/*******************************************************************************
diff --git a/system/stack/fuzzers/rfcomm_fuzzer.cc b/system/stack/fuzzers/rfcomm_fuzzer.cc
index 3418f3a6ed..82897723c6 100644
--- a/system/stack/fuzzers/rfcomm_fuzzer.cc
+++ b/system/stack/fuzzers/rfcomm_fuzzer.cc
@@ -52,10 +52,6 @@ void SnoopLogger::AcceptlistRfcommDlci(uint16_t, uint16_t, uint8_t) {}
void SnoopLogger::SetRfcommPortOpen(uint16_t, uint16_t, uint8_t, uint16_t, bool) {}
void SnoopLogger::SetRfcommPortClose(uint16_t, uint16_t, uint8_t, uint16_t) {}
} // namespace hal
-
-namespace common {
-uint64_t time_get_os_boottime_ms() { return 0; }
-} // namespace common
} // namespace bluetooth
namespace {
diff --git a/system/stack/gatt/gatt_attr.cc b/system/stack/gatt/gatt_attr.cc
index a9d9e12b66..7b629e18e2 100644
--- a/system/stack/gatt/gatt_attr.cc
+++ b/system/stack/gatt/gatt_attr.cc
@@ -33,10 +33,12 @@
#include "eatt/eatt.h"
#include "gatt_api.h"
#include "gatt_int.h"
+#include "device/include/interop.h"
#include "internal_include/bt_target.h"
#include "stack/include/bt_types.h"
#include "stack/include/bt_uuid16.h"
#include "stack/include/btm_sec_api.h"
+#include "stack/include/btm_ble_addr.h"
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
@@ -847,6 +849,7 @@ static bool read_sr_sirk_req(tCONN_ID conn_id,
uint8_t sirk_type, Octet16& sirk)>
cb) {
tGATT_READ_PARAM param = {};
+ tBLE_ADDR_TYPE address_type = BLE_ADDR_PUBLIC;
param.service.s_handle = 1;
param.service.e_handle = 0xFFFF;
@@ -854,10 +857,27 @@ static bool read_sr_sirk_req(tCONN_ID conn_id,
param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_CSIS_SIRK);
- if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, &param) != GATT_SUCCESS) {
- log::error("Read GATT Support features GATT_Read Failed, conn_id: {}",
- static_cast<int>(conn_id));
- return false;
+ uint8_t tcb_idx = gatt_get_tcb_idx(conn_id);
+ tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
+
+ RawAddress identity_address = tcb.peer_bda;
+
+ btm_random_pseudo_to_identity_addr(&identity_address, &address_type);
+
+ if (address_type == BLE_ADDR_PUBLIC &&
+ interop_match_addr(INTEROP_DISABLE_SIRK_READ_BY_TYPE, &identity_address)) {
+ if (GATTC_Read(conn_id, GATT_READ_CHAR_VALUE, &param) != GATT_SUCCESS) {
+ log::error("Read GATT Support features GATT_Read Failed, conn_id: {}",
+ static_cast<int>(conn_id));
+ return false;
+ }
+ }
+ else{
+ if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, &param) != GATT_SUCCESS) {
+ log::error("Read GATT Support features GATT_Read Failed, conn_id: {}",
+ static_cast<int>(conn_id));
+ return false;
+ }
}
gatt_op_cb_data cb_data;
diff --git a/system/stack/include/a2dp_vendor_ldac.h b/system/stack/include/a2dp_vendor_ldac.h
index ec755c3b72..8f323a8c90 100644
--- a/system/stack/include/a2dp_vendor_ldac.h
+++ b/system/stack/include/a2dp_vendor_ldac.h
@@ -56,17 +56,6 @@ private:
void debug_codec_dump(int fd) override;
};
-class A2dpCodecConfigLdacSink : public A2dpCodecConfigLdacBase {
-public:
- A2dpCodecConfigLdacSink(btav_a2dp_codec_priority_t codec_priority);
- virtual ~A2dpCodecConfigLdacSink();
-
- bool init() override;
-
-private:
- bool useRtpHeaderMarkerBit() const override;
-};
-
// Checks whether the codec capabilities contain a valid A2DP LDAC Source
// codec.
// NOTE: only codecs that are implemented are considered valid.
@@ -166,13 +155,6 @@ std::string A2DP_VendorCodecInfoStringLdac(const uint8_t* p_codec_info);
// supported, otherwise NULL.
const tA2DP_ENCODER_INTERFACE* A2DP_VendorGetEncoderInterfaceLdac(const uint8_t* p_codec_info);
-// Gets the current A2DP LDAC decoder interface that can be used to decode
-// received A2DP packets - see |tA2DP_DECODER_INTERFACE|.
-// |p_codec_info| contains the codec information.
-// Returns the A2DP LDAC decoder interface if the |p_codec_info| is valid and
-// supported, otherwise NULL.
-const tA2DP_DECODER_INTERFACE* A2DP_VendorGetDecoderInterfaceLdac(const uint8_t* p_codec_info);
-
// Adjusts the A2DP LDAC codec, based on local support and Bluetooth
// specification.
// |p_codec_info| contains the codec information to adjust.
@@ -184,23 +166,11 @@ bool A2DP_VendorAdjustCodecLdac(uint8_t* p_codec_info);
// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
btav_a2dp_codec_index_t A2DP_VendorSourceCodecIndexLdac(const uint8_t* p_codec_info);
-// Gets the A2DP LDAC Sink codec index for a given |p_codec_info|.
-// Returns the corresponding |btav_a2dp_codec_index_t| on success,
-// otherwise |BTAV_A2DP_CODEC_INDEX_MAX|.
-btav_a2dp_codec_index_t A2DP_VendorSinkCodecIndexLdac(const uint8_t* p_codec_info);
-
// Gets the A2DP LDAC Source codec name.
const char* A2DP_VendorCodecIndexStrLdac(void);
-// Gets the A2DP LDAC Sink codec name.
-const char* A2DP_VendorCodecIndexStrLdacSink(void);
-
// Initializes A2DP LDAC Source codec information into |AvdtpSepConfig|
// configuration entry pointed by |p_cfg|.
bool A2DP_VendorInitCodecConfigLdac(AvdtpSepConfig* p_cfg);
-// Initializes A2DP LDAC Sink codec information into |AvdtpSepConfig|
-// configuration entry pointed by |p_cfg|.
-bool A2DP_VendorInitCodecConfigLdacSink(AvdtpSepConfig* p_cfg);
-
#endif // A2DP_VENDOR_LDAC_H
diff --git a/system/stack/include/a2dp_vendor_ldac_decoder.h b/system/stack/include/a2dp_vendor_ldac_decoder.h
deleted file mode 100644
index 3d15b8397a..0000000000
--- a/system/stack/include/a2dp_vendor_ldac_decoder.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2016 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.
- */
-
-//
-// Interface to the A2DP LDAC Decoder
-//
-
-#ifndef A2DP_VENDOR_LDAC_DECODER_H
-#define A2DP_VENDOR_LDAC_DECODER_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "a2dp_codec_api.h"
-#include "stack/include/bt_hdr.h"
-
-// Loads the A2DP LDAC decoder.
-// Return true on success, otherwise false.
-bool A2DP_VendorLoadDecoderLdac(void);
-
-// Unloads the A2DP LDAC decoder.
-void A2DP_VendorUnloadDecoderLdac(void);
-
-// Initialize the A2DP LDAC decoder.
-bool a2dp_vendor_ldac_decoder_init(decoded_data_callback_t decode_callback);
-
-// Cleanup the A2DP LDAC decoder.
-void a2dp_vendor_ldac_decoder_cleanup(void);
-
-// Decodes |p_buf|. Calls |decode_callback| passed into
-// |a2dp_vendor_ldac_decoder_init| if decoded frames are available.
-bool a2dp_vendor_ldac_decoder_decode_packet(BT_HDR* p_buf);
-
-// Start the A2DP LDAC decoder.
-void a2dp_vendor_ldac_decoder_start(void);
-
-// Suspend the A2DP LDAC decoder.
-void a2dp_vendor_ldac_decoder_suspend(void);
-
-// A2DP LDAC decoder configuration.
-void a2dp_vendor_ldac_decoder_configure(const uint8_t* p_codec_info);
-
-#endif // A2DP_VENDOR_LDAC_DECODER_H
diff --git a/system/stack/include/avrc_api.h b/system/stack/include/avrc_api.h
index 589ddb5021..b2f683cc0c 100644
--- a/system/stack/include/avrc_api.h
+++ b/system/stack/include/avrc_api.h
@@ -133,10 +133,6 @@
#define AVRC_1_3_STRING "avrcp13"
#endif
-#ifndef AVRC_DEFAULT_VERSION
-#define AVRC_DEFAULT_VERSION AVRC_1_5_STRING
-#endif
-
/* Configurable dynamic avrcp version enable key*/
#ifndef AVRC_DYNAMIC_AVRCP_ENABLE_PROPERTY
#define AVRC_DYNAMIC_AVRCP_ENABLE_PROPERTY "persist.bluetooth.dynamic_avrcp.enable"
diff --git a/system/stack/include/ble_appearance.h b/system/stack/include/ble_appearance.h
new file mode 100644
index 0000000000..6dbb32996c
--- /dev/null
+++ b/system/stack/include/ble_appearance.h
@@ -0,0 +1,446 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2025 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.
+ *
+ ******************************************************************************/
+
+#ifndef BLE_APPEARANCE_H
+#define BLE_APPEARANCE_H
+
+/* BLE appearance values as per BT spec assigned numbers */
+/* Category[15:6] 0x000 */
+#define BLE_APPEARANCE_UNKNOWN 0x0000
+
+/* Category[15:6] 0x001 */
+#define BLE_APPEARANCE_GENERIC_PHONE 0x0040
+
+/* Category[15:6] 0x002 */
+#define BLE_APPEARANCE_GENERIC_COMPUTER 0x0080
+
+#define BLE_APPEARANCE_DESKTOP_WORKSTATION 0x81
+#define BLE_APPEARANCE_SERVER_CLASS_COMPUTER 0x82
+#define BLE_APPEARANCE_LAPTOP 0x83
+#define BLE_APPEARANCE_HANDHELD_PC_PDA 0x84
+#define BLE_APPEARANCE_PALM_SIZE_PC_PDA 0x85
+#define BLE_APPEARANCE_WEARABLE_COMPUTER_WATCH_SIZE 0x86
+#define BLE_APPEARANCE_TABLET 0x87
+#define BLE_APPEARANCE_DOCKING_STATION 0x88
+#define BLE_APPEARANCE_ALL_IN_ONE 0x89
+#define BLE_APPEARANCE_BLADE_SERVER 0x8A
+#define BLE_APPEARANCE_CONVERTIBLE 0x8B
+#define BLE_APPEARANCE_DETACHABLE 0x8C
+#define BLE_APPEARANCE_IOT_GATEWAY 0x8D
+#define BLE_APPEARANCE_MINI_PC 0x8E
+#define BLE_APPEARANCE_STICK_PC 0x8F
+
+/* Category[15:6] 0x003 */
+#define BLE_APPEARANCE_GENERIC_WATCH 0x00C0
+#define BLE_APPEARANCE_SPORTS_WATCH 0x00C1
+#define BLE_APPEARANCE_SMART_WATCH 0x00C2
+
+/* Category[15:6] 0x004 */
+#define BLE_APPEARANCE_GENERIC_CLOCK 0x0100
+
+/* Category[15:6] 0x005 */
+#define BLE_APPEARANCE_GENERIC_DISPLAY 0x0140
+
+/* Category[15:6] 0x006 */
+#define BLE_APPEARANCE_GENERIC_REMOTE 0x0180
+
+/* Category[15:6] 0x007 */
+#define BLE_APPEARANCE_GENERIC_EYEGLASSES 0x01C0
+
+/* Category[15:6] 0x008 */
+#define BLE_APPEARANCE_GENERIC_TAG 0x0200
+
+/* Category[15:6] 0x009 */
+#define BLE_APPEARANCE_GENERIC_KEYRING 0x0240
+
+/* Category[15:6] 0x00A */
+#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280
+
+/* Category[15:6] 0x00B */
+#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0
+
+/* Category[15:6] 0x00C */
+#define BLE_APPEARANCE_GENERIC_THERMOMETER 0x0300
+#define BLE_APPEARANCE_THERMOMETER_EAR 0x0301
+
+/* Category[15:6] 0x00D */
+#define BLE_APPEARANCE_GENERIC_HEART_RATE 0x0340
+#define BLE_APPEARANCE_HEART_RATE_BELT 0x0341
+
+/* Category[15:6] 0x00E */
+#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380
+#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381
+#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382
+
+/* Category[15:6] 0x00F */
+#define BLE_APPEARANCE_GENERIC_HID 0x03C0
+#define BLE_APPEARANCE_HID_KEYBOARD 0x03C1
+#define BLE_APPEARANCE_HID_MOUSE 0x03C2
+#define BLE_APPEARANCE_HID_JOYSTICK 0x03C3
+#define BLE_APPEARANCE_HID_GAMEPAD 0x03C4
+#define BLE_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5
+#define BLE_APPEARANCE_HID_CARD_READER 0x03C6
+#define BLE_APPEARANCE_HID_DIGITAL_PEN 0x03C7
+#define BLE_APPEARANCE_HID_BARCODE_SCANNER 0x03C8
+#define BLE_APPEARANCE_HID_TOUCHPAD 0x03C9
+#define BLE_APPEARANCE_HID_PRESENTATION_REMOTE 0x03CA
+
+/* Category[15:6] 0x010 */
+#define BLE_APPEARANCE_GENERIC_GLUCOSE 0x0400
+
+/* Category[15:6] 0x011 */
+#define BLE_APPEARANCE_GENERIC_WALKING 0x0440
+#define BLE_APPEARANCE_WALKING_IN_SHOE 0x0441
+#define BLE_APPEARANCE_WALKING_ON_SHOE 0x0442
+#define BLE_APPEARANCE_WALKING_ON_HIP 0x0443
+
+/* Category[15:6] 0x012 */
+#define BLE_APPEARANCE_GENERIC_CYCLING 0x0480
+#define BLE_APPEARANCE_CYCLING_COMPUTER 0x0481
+#define BLE_APPEARANCE_CYCLING_SPEED 0x0482
+#define BLE_APPEARANCE_CYCLING_CADENCE 0x0483
+#define BLE_APPEARANCE_CYCLING_POWER 0x0484
+#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485
+
+/* Category[15:6] 0x013 */
+#define BLE_APPEARANCE_GENERIC_CONTROL_DEVICE 0x04C0
+#define BLE_APPEARANCE_SWITCH 0x04C1
+#define BLE_APPEARANCE_MULTI_SWITCH 0x04C2
+#define BLE_APPEARANCE_SWITCH_BUTTON 0x04C3
+#define BLE_APPEARANCE_SWITCH_SLIDER 0x04C4
+#define BLE_APPEARANCE_ROTARY_SWITCH 0x04C5
+#define BLE_APPEARANCE_TOUCH_PANEL 0x04C6
+#define BLE_APPEARANCE_SINGLE_SWITCH 0x04C7
+#define BLE_APPEARANCE_DOUBLE_SWITCH 0x04C8
+#define BLE_APPEARANCE_TRIPLE_SWITCH 0x04C9
+#define BLE_APPEARANCE_BATTERY_SWITCH 0x04CA
+#define BLE_APPEARANCE_ENERGY_HARVESTING_SWITCH 0x04CB
+#define BLE_APPEARANCE_SWITCH_PUSH_BUTTON 0x04CC
+#define BLE_APPEARANCE_SWITCH_DIAL 0x04CD
+
+/* Category[15:6] 0x014 */
+#define BLE_APPEARANCE_GENERIC_NETWORK_DEVICE 0x0500
+#define BLE_APPEARANCE_NETWORK_DEVICE_ACCESS_POINT 0x0501
+#define BLE_APPEARANCE_NETWORK_DEVICE_MESH_DEVICE 0x0502
+#define BLE_APPEARANCE_NETWORK_DEVICE_MESH_NETWORK_PROXY 0x0503
+
+/* Category[15:6] 0x015 */
+#define BLE_APPEARANCE_GENERIC_SENSOR 0x0540
+#define BLE_APPEARANCE_MOTION_SENSOR 0x0541
+#define BLE_APPEARANCE_AIR_QUALITY_SENSOR 0x0542
+#define BLE_APPEARANCE_TEMPERATURE_SENSOR 0x0543
+#define BLE_APPEARANCE_HUMIDITY_SENSOR 0x0544
+#define BLE_APPEARANCE_LEAK_SENSOR 0x05
+#define BLE_APPEARANCE_SMOKE_SENSOR 0x0546
+#define BLE_APPEARANCE_OCCUPANCY_SENSOR 0x0547
+#define BLE_APPEARANCE_CONTACT_SENSOR 0x0548
+#define BLE_APPEARANCE_CARBON_MONOXIDE_SENSOR 0x0549
+#define BLE_APPEARANCE_CARBON_DIOXIDE_SENSOR 0x054A
+#define BLE_APPEARANCE_AMBIENT_LIGHT_SENSOR 0x054B
+#define BLE_APPEARANCE_ENERGY_SENSOR 0x054C
+#define BLE_APPEARANCE_COLOR_LIGHT_SENSOR 0x054D
+#define BLE_APPEARANCE_RAIN_SENSOR 0x054E
+#define BLE_APPEARANCE_FIRE_SENSOR 0x054F
+#define BLE_APPEARANCE_WIND_SENSOR 0x0550
+#define BLE_APPEARANCE_PROXIMITY_SENSOR 0x0551
+#define BLE_APPEARANCE_MULTI_SENSOR 0x0552
+#define BLE_APPEARANCE_FLUSH_MOUNTED_SENSOR 0x0553
+#define BLE_APPEARANCE_CEILING_MOUNTED_SENSOR 0x0554
+#define BLE_APPEARANCE_WALL_MOUNTED_SENSOR 0x0555
+#define BLE_APPEARANCE_MULTISENSOR 0x0556
+#define BLE_APPEARANCE_SENSOR_ENERGY_METER 0x0557
+#define BLE_APPEARANCE_SENSOR_FLAME_DETECTOR 0x0558
+#define BLE_APPEARANCE_VEHICLE_TIRE_PRESSURE_SENSOR 0x0559
+
+/* Category[15:6] 0x016 */
+#define BLE_APPEARANCE_GENERIC_LIGHT_FIXTURE 0x0580
+#define BLE_APPEARANCE_WALL_LIGHT 0x0581
+#define BLE_APPEARANCE_CEILING_LIGHT 0x0582
+#define BLE_APPEARANCE_FLOOR_LIGHT 0x0583
+#define BLE_APPEARANCE_CABINET_LIGHT 0x0584
+#define BLE_APPEARANCE_DESK_LIGHT 0x0585
+#define BLE_APPEARANCE_TROFFER_LIGHT 0x0586
+#define BLE_APPEARANCE_PENDANT_LIGHT 0x0587
+#define BLE_APPEARANCE_IN_GROUND_LIGHT 0x0588
+#define BLE_APPEARANCE_FLOOD_LIGHT 0x0589
+#define BLE_APPEARANCE_UNDERWATER_LIGHT 0x058A
+#define BLE_APPEARANCE_BOLLARD_WITH_LIGHT 0x058B
+#define BLE_APPEARANCE_PATHWAY_LIGHT 0x058C
+#define BLE_APPEARANCE_GARDEN_LIGHT 0x058D
+#define BLE_APPEARANCE_POLE_TOP_LIGHT 0x058E
+#define BLE_APPEARANCE_SPOTLIGHT 0x058F
+#define BLE_APPEARANCE_LINEAR_LIGHT 0x0590
+#define BLE_APPEARANCE_STREET_LIGHT 0x0591
+#define BLE_APPEARANCE_SHELVES_LIGHT 0x0592
+#define BLE_APPEARANCE_BAY_LIGHT 0x0593
+#define BLE_APPEARANCE_EMERGENCY_EXIT_LIGHT 0x0594
+#define BLE_APPEARANCE_LIGHT_CONTROLLER 0x0595
+#define BLE_APPEARANCE_LIGHT_DRIVER 0x0596
+#define BLE_APPEARANCE_BULB 0x0597
+#define BLE_APPEARANCE_LOW_BAY_LIGHT 0x0598
+#define BLE_APPEARANCE_HIGH_BAY_LIGHT 0x0599
+
+/* Category[15:6] 0x017 */
+#define BLE_APPEARANCE_GENERIC_FAN 0x05C0
+#define BLE_APPEARANCE_CEILING_FAN 0x05C1
+#define BLE_APPEARANCE_AXIAL_FAN 0x05C2
+#define BLE_APPEARANCE_EXHAUST_FAN 0x05C3
+#define BLE_APPEARANCE_PEDESTAL_FAN 0x05C4
+#define BLE_APPEARANCE_DESK_FAN 0x05C5
+#define BLE_APPEARANCE_WALL_FAN 0x05C6
+
+/* Category[15:6] 0x018 */
+#define BLE_APPEARANCE_GENERIC_HVAC 0x0600
+#define BLE_APPEARANCE_HVAC_THERMOSTAT 0x0601
+#define BLE_APPEARANCE_HVAC_HUMIDIFIER 0x0602
+#define BLE_APPEARANCE_HVAC_DEHUMIDIFIER 0x0603
+#define BLE_APPEARANCE_HVAC_HEATER 0x0604
+#define BLE_APPEARANCE_HVAC_RADIATOR 0x0605
+#define BLE_APPEARANCE_HVAC_BOILER 0x0606
+#define BLE_APPEARANCE_HVAC_HEAT_PUMP 0x0607
+#define BLE_APPEARANCE_HVAC_INFRARED_HEATER 0x0608
+#define BLE_APPEARANCE_HVAC_RADIANT_PANEL_HEATER 0x0609
+#define BLE_APPEARANCE_HVAC_FAN_HEATER 0x060A
+#define BLE_APPEARANCE_HVAC_AIR_CURTAIN 0x060B
+
+/* Category[15:6] 0x019 */
+#define BLE_APPEARANCE_GENERIC_AIR_CONDITIONING 0x0640
+
+/* Category[15:6] 0x01A */
+#define BLE_APPEARANCE_GENERIC_HUMIDIFIER 0x0680
+
+/* Category[15:6] 0x01B */
+#define BLE_APPEARANCE_GENERIC_HEATING 0x06C0
+#define BLE_APPEARANCE_HEATING_RADIATOR 0x06C1
+#define BLE_APPEARANCE_HEATING_BOILER 0x06C2
+#define BLE_APPEARANCE_HEATING_HEAT_PUMP 0x06C3
+#define BLE_APPEARANCE_HEATING_INFRARED_HEATER 0x06C4
+#define BLE_APPEARANCE_HEATING_RADIANT_PANEL_HEATER 0x06C5
+#define BLE_APPEARANCE_HEATING_FAN_HEATER 0x06C6
+#define BLE_APPEARANCE_HEATING_AIR_CURTAIN 0x06C7
+
+/* Category[15:6] 0x01C */
+#define BLE_APPEARANCE_GENERIC_ACCESS_CONTROL 0x0700
+#define BLE_APPEARANCE_ACCESS_DOOR 0x0701
+#define BLE_APPEARANCE_ACCESS_CONTROL_GARAGE_DOOR 0x0702
+#define BLE_APPEARANCE_ACCESS_CONTROL_EMERGENCY_EXIT_DOOR 0x0703
+#define BLE_APPEARANCE_ACCESS_CONTROL_ACCESS_LOCK 0x0704
+#define BLE_APPEARANCE_ACCESS_CONTROL_ELEVATOR 0x0705
+#define BLE_APPEARANCE_ACCESS_CONTROL_WINDOW 0x0706
+#define BLE_APPEARANCE_ACCESS_CONTROL_ENTRANCE_GATE 0x0707
+#define BLE_APPEARANCE_ACCESS_CONTROL_DOOR_LOCK 0x0708
+#define BLE_APPEARANCE_ACCESS_CONTROL_LOCKER 0x0709
+
+/* Category[15:6] 0x01D */
+#define BLE_APPEARANCE_GENERIC_MOTORIZED_DEVICE 0x0740
+#define BLE_APPEARANCE_MOTORIZED_GATE 0x0741
+#define BLE_APPEARANCE_MOTORIZED_AWNING 0x0742
+#define BLE_APPEARANCE_MOTORIZED_BLINDS_OR_SHADES 0x0743
+#define BLE_APPEARANCE_MOTORIZED_CURTAINS 0x0744
+#define BLE_APPEARANCE_MOTORIZED_SCREEN 0x0745
+
+/* Category[15:6] 0x01E */
+#define BLE_APPEARANCE_GENERIC_POWER_DEVICE 0x0780
+#define BLE_APPEARANCE_POWER_OUTLET 0x0781
+#define BLE_APPEARANCE_POWER_STRIP 0x0782
+#define BLE_APPEARANCE_POWER_PLUG 0x0783
+#define BLE_APPEARANCE_POWER_SUPPLY 0x0784
+
+/* Category[15:6] 0x01F */
+#define BLE_APPEARANCE_GENERIC_LIGHT_SOURCE 0x07C0
+#define BLE_APPEARANCE_LIGHT_SOURCE_INCANDESCENT_LIGHT_BULB 0x07C1
+#define BLE_APPEARANCE_LIGHT_SOURCE_LED_LAMP 0x07C2
+#define BLE_APPEARANCE_LIGHT_SOURCE_HID_LAMP 0x07C3
+#define BLE_APPEARANCE_LIGHT_SOURCE_FLUORESCENT_LAMP 0x07C4
+#define BLE_APPEARANCE_LIGHT_SOURCE_LED_ARRAY 0x07C5
+#define BLE_APPEARANCE_LIGHT_SOURCE_MULTI_COLOR_LED_ARRAY 0x07C6
+#define BLE_APPEARANCE_LIGHT_SOURCE_LOW_VOLTAGE_HALOGEN 0x07C7
+#define BLE_APPEARANCE_LIGHT_SOURCE_ORGANIC_LIGHT_EMITTING_DIODE_OLED 0x07C8
+
+/* Category[15:6] 0x020 */
+#define BLE_APPEARANCE_GENERIC_WINDOW_COVERING 0x0800
+#define BLE_APPEARANCE_WINDOW_COVERING_WINDOW_SHADES 0x0801
+#define BLE_APPEARANCE_WINDOW_COVERING_WINDOW_BLINDS 0x0802
+#define BLE_APPEARANCE_WINDOW_COVERING_WINDOW_AWNING 0x0803
+#define BLE_APPEARANCE_WINDOW_COVERING_WINDOW_CURTAIN 0x0804
+#define BLE_APPEARANCE_WINDOW_COVERING_EXTERIOR_SHUTTER 0x0805
+#define BLE_APPEARANCE_WINDOW_COVERING_EXTERIOR_SCREEN 0x0806
+
+/* Category[15:6] 0x021 */
+#define BLE_APPEARANCE_GENERIC_AUDIO_SINK 0x0840
+#define BLE_APPEARANCE_AUDIO_SINK_STANDALONE_SPEAKER 0x0841
+#define BLE_APPEARANCE_AUDIO_SINK_SOUNDBAR 0x0842
+#define BLE_APPEARANCE_AUDIO_SINK_BOOKSHELF_SPEAKER 0x0843
+#define BLE_APPEARANCE_AUDIO_SINK_STANDMOUNTED_SPEAKER 0x0844
+#define BLE_APPEARANCE_AUDIO_SINK_SPEAKERPHONE 0x0845
+
+/* Category[15:6] 0x022 */
+#define BLE_APPEARANCE_GENERIC_AUDIO_SOURCE 0x0880
+#define BLE_APPEARANCE_AUDIO_SOURCE_MICROPHONE 0x0881
+#define BLE_APPEARANCE_AUDIO_SOURCE_ALARM 0x0882
+#define BLE_APPEARANCE_AUDIO_SOURCE_BELL 0x0883
+#define BLE_APPEARANCE_AUDIO_SOURCE_HORN 0x0884
+#define BLE_APPEARANCE_AUDIO_SOURCE_BROADCASTING_DEVICE 0x0885
+#define BLE_APPEARANCE_AUDIO_SOURCE_SERVICE_DESK 0x0886
+#define BLE_APPEARANCE_AUDIO_SOURCE_KIOSK 0x0887
+#define BLE_APPEARANCE_AUDIO_SOURCE_BROADCASTING_ROOM 0x0888
+#define BLE_APPEARANCE_AUDIO_SOURCE_AUDITORIUM 0x0889
+
+/* Category[15:6] 0x023 */
+#define BLE_APPEARANCE_GENERIC_MOTORIZED_VEHICLE 0x08C0
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_CAR 0x08C1
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_LARGE_GOODS 0x08C2
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_2_WHEELED 0x08C3
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_MOTORBIKE 0x08C4
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_SCOOTER 0x08C5
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_MOPED 0x08C6
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_3_WHEELED 0x08C7
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_LIGHT_VEHICLE 0x08C8
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_QUAD_BIKE 0x08C9
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_MINIBUS 0x08CA
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_BUS 0x08CB
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_TROLLEY 0x08CC
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_AGRICULTURAL_VEHICLE 0x08CD
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_CAMPER_CARAVAN 0x08CE
+#define BLE_APPEARANCE_MOTORIZED_VEHICLE_RECREATIONAL_VEHICLE_MOTOR_HOME 0x08CF
+
+/* Category[15:6] 0x024 */
+#define BLE_APPEARANCE_GENERIC_DOMESTIC_APPLIANCE 0x0900
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_REFRIGERATOR 0x0901
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_FREEZER 0x0902
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_OVEN 0x0903
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_MICROWAVE 0x0904
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_TOASTER 0x0905
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_WASHING_MACHINE 0x0906
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_DRYER 0x0907
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_COFFEE_MAKER 0x0908
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_CLOTHES_IRON 0x0909
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_CURLING_IRON 0x090A
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_HAIR_DRYER 0x090B
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_VACUUM_CLEANER 0x090C
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_ROBOTIC_VACUUM_CLEANER 0x090D
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_RICE_COOKER 0x090E
+#define BLE_APPEARANCE_DOMESTIC_APPLIANCE_CLOTHES_STEAMER 0x090F
+
+/* Category[15:6] 0x025 */
+#define BLE_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE 0x0940
+#define BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941
+#define BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET 0x0942
+#define BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES 0x0943
+#define BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND 0x0944
+
+/* Category[15:6] 0x026 */
+#define BLE_APPEARANCE_GENERIC_AIRCRAFT 0x0980
+#define BLE_APPEARANCE_AIRCRAFT_LIGHT 0x0981
+#define BLE_APPEARANCE_AIRCRAFT_MICROLIGHT 0x0982
+#define BLE_APPEARANCE_AIRCRAFT_PARAGLIDER 0x0983
+#define BLE_APPEARANCE_AIRCRAFT_LARGE_PASSENGER 0x0984
+
+/* Category[15:6] 0x027 */
+#define BLE_APPEARANCE_GENERIC_AV_EQUIPMENT 0x09C0
+#define BLE_APPEARANCE_AV_EQUIPMENT_AMPLIFIER 0x09C1
+#define BLE_APPEARANCE_AV_EQUIPMENT_RECEIVER 0x09C2
+#define BLE_APPEARANCE_AV_EQUIPMENT_RADIO 0x09C3
+#define BLE_APPEARANCE_AV_EQUIPMENT_TUNER 0x09C4
+#define BLE_APPEARANCE_AV_EQUIPMENT_TURNTABLE 0x09C5
+#define BLE_APPEARANCE_AV_EQUIPMENT_CD_PLAYER 0x09C6
+#define BLE_APPEARANCE_AV_EQUIPMENT_DVD_PLAYER 0x09C7
+#define BLE_APPEARANCE_AV_EQUIPMENT_BLU_RAY_PLAYER 0x09C8
+#define BLE_APPEARANCE_AV_EQUIPMENT_OPTICAL_DISC_PLAYER 0x09C9
+#define BLE_APPEARANCE_AV_EQUIPMENT_SET_TOP_BOX 0x09CA
+
+/* Category[15:6] 0x028 */
+#define BLE_APPEARANCE_GENERIC_DISPLAY_EQUIPMENT 0x0A00
+#define BLE_APPEARANCE_DISPLAY_EQUIPMENT_TELEVISION 0x0A01
+#define BLE_APPEARANCE_DISPLAY_EQUIPMENT_MONITOR 0x0A02
+#define BLE_APPEARANCE_DISPLAY_EQUIPMENT_PROJECTOR 0x0A03
+
+/* Category[15:6] 0x029 */
+#define BLE_APPEARANCE_GENERIC_HEARING_AID 0x0A40
+#define BLE_APPEARANCE_HEARING_AID_IN_EAR 0x0A41
+#define BLE_APPEARANCE_HEARING_AID_BEHIND_EAR 0x0A42
+#define BLE_APPEARANCE_HEARING_AID_COCHLLEAR_IMPLANT 0x0A43
+
+/* Category[15:6] 0x02A */
+#define BLE_APPEARANCE_GENERIC_GAMING 0x0A80
+#define BLE_APPEARANCE_GAMING_HOME_VIDEO_GAME_CONSOLE 0x0A81
+#define BLE_APPEARANCE_GAMING_PORTABLE_HANDHELD_CONSOLE 0x0A82
+
+/* Category[15:6] 0x02B */
+#define BLE_APPEARANCE_GENERIC_SIGNAGE 0x0AC0
+#define BLE_APPEARANCE_SIGNAGE_DIGITAL 0x0AC1
+#define BLE_APPEARANCE_SIGNAGE_ELECTRONIC_LABEL 0x0AC2
+
+/* Category[15:6] 0x031 */
+#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40
+#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41
+#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42
+
+/* Category[15:6] 0x032 */
+#define BLE_APPEARANCE_GENERIC_WEIGHT 0x0C80
+
+/* Category[15:6] 0x033 */
+#define BLE_APPEARANCE_GENERIC_PERSONAL_MOBILITY_DEVICE 0x0CC0
+#define BLE_APPEARANCE_PERSONAL_MOBILITY_DEVICE_POWERED_WHEELCHAIR 0x0CC1
+#define BLE_APPEARANCE_PERSONAL_MOBILITY_DEVICE_MOBILITY_SCOOTER 0x0CC2
+
+/* Category[15:6] 0x034 */
+#define BLE_APPEARANCE_GENERIC_CONTINUOUS_GLUCOSE_MONITOR 0x0D00
+
+/* Category[15:6] 0x035 */
+#define BLE_APPEARANCE_GENERIC_INSULIN_PUMP 0x0D40
+#define BLE_APPEARANCE_INSULIN_PUMP_DURABLE 0x0D41
+#define BLE_APPEARANCE_INSULIN_PUMP_PATCH 0x0D44
+#define BLE_APPEARANCE_INSULIN_PUMP_PEN 0x0D48
+
+/* Category[15:6] 0x036 */
+#define BLE_APPEARANCE_GENERIC_MEDICATION_DELIVERY 0x0D80
+
+/* Category[15:6] 0x037 */
+#define BLE_APPEARANCE_GENERIC_SPIROMETER 0x0DC0
+#define BLE_APPEARANCE_SPIROMETER_HANDHELD 0x0DC1
+
+/* Category[15:6] 0x051 */
+#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443
+#define BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444
+
+/* Category[15:6] 0x052 */
+#define BLE_APPEARANCE_GENERIC_INDUSTRIAL_MEASUREMENT_DEVICE 0x1480
+#define BLE_APPEARANCE_INDUSTRIAL_MEASUREMENT_DEVICE_TORQUE_TESTING 0x1481
+#define BLE_APPEARANCE_INDUSTRIAL_MEASUREMENT_DEVICE_CALIPER 0x1482
+#define BLE_APPEARANCE_INDUSTRIAL_MEASUREMENT_DEVICE_DIAL_INDICATOR 0x1483
+#define BLE_APPEARANCE_INDUSTRIAL_MEASUREMENT_DEVICE_MICROMETER 0x1484
+#define BLE_APPEARANCE_INDUSTRIAL_MEASUREMENT_DEVICE_HEIGHT_GAUGE 0x1485
+#define BLE_APPEARANCE_INDUSTRIAL_MEASUREMENT_DEVICE_FORCE_GAUGE 0x1486
+
+/* Category[15:6] 0x053 */
+#define BLE_APPEARANCE_GENERIC_INDUSTRIAL_TOOLS 0x14C0
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_MACHINE_TOOL_HOLDER 0x14C1
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_GENERIC_CLAMPING_DEVICE 0x14C2
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_CLAMPING_JAWS_JAWS_CHUCK 0x14C3
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_CLAMPING_COLLET_CHUCK 0x14C4
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_CLAMPING_MANDREL 0x14C5
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_VISE 0x14C6
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_ZERO_POINT_CLAMPING_SYSTEM 0x14C7
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_TORQUE_WRENCH 0x14C8
+#define BLE_APPEARANCE_INDUSTRIAL_TOOLS_TORQUE_SCREWDRIVER 0x14C9
+
+#endif // BLE_APPEARANCE_H \ No newline at end of file
diff --git a/system/stack/include/ble_hci_link_interface.h b/system/stack/include/ble_hci_link_interface.h
index 068368bfb6..41f689ecab 100644
--- a/system/stack/include/ble_hci_link_interface.h
+++ b/system/stack/include/ble_hci_link_interface.h
@@ -18,8 +18,10 @@
#pragma once
#include <cstdint>
+#include <vector>
#include "stack/include/hci_error_code.h"
+#include "stack/include/rnr_interface.h"
// This header contains functions for HCI-ble to invoke
void btm_ble_read_remote_features_complete(uint8_t* p, uint8_t length);
@@ -30,3 +32,21 @@ void btm_ble_read_resolving_list_entry_complete(const uint8_t* p, uint16_t evt_l
void btm_ble_remove_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len);
void btm_ble_add_resolving_list_entry_complete(uint8_t* p, uint16_t evt_len);
void btm_ble_clear_resolving_list_complete(uint8_t* p, uint16_t evt_len);
+tBTM_STATUS btm_ble_read_remote_cod(const RawAddress& remote_bda);
+tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb);
+bool btm_ble_cancel_remote_name(const RawAddress& remote_bda);
+void btm_ble_decrement_link_topology_mask(uint8_t link_role);
+void btm_ble_increment_link_topology_mask(uint8_t link_role);
+DEV_CLASS btm_ble_get_appearance_as_cod(std::vector<uint8_t> const& data);
+void btm_ble_process_adv_addr(RawAddress& raw_address, tBLE_ADDR_TYPE* address_type);
+void btm_ble_process_adv_pkt_cont_for_inquiry(uint16_t event_type, tBLE_ADDR_TYPE address_type,
+ const RawAddress& raw_address, uint8_t primary_phy,
+ uint8_t secondary_phy, uint8_t advertising_sid,
+ int8_t tx_power, int8_t rssi,
+ uint16_t periodic_adv_int,
+ std::vector<uint8_t> advertising_data);
+void btm_ble_process_adv_pkt_cont(uint16_t evt_type, tBLE_ADDR_TYPE addr_type,
+ const RawAddress& bda, uint8_t primary_phy, uint8_t secondary_phy,
+ uint8_t advertising_sid, int8_t tx_power, int8_t rssi,
+ uint16_t periodic_adv_int, uint8_t data_len, const uint8_t* data,
+ const RawAddress& original_bda);
diff --git a/system/stack/include/bt_dev_class.h b/system/stack/include/bt_dev_class.h
index 1455f66fd2..ca951532ce 100644
--- a/system/stack/include/bt_dev_class.h
+++ b/system/stack/include/bt_dev_class.h
@@ -26,72 +26,222 @@ typedef std::array<uint8_t, kDevClassLength> DEV_CLASS; /* Device class */
inline constexpr DEV_CLASS kDevClassEmpty = {};
+/***************************
+ * major device class field
+ * Note: All values are deduced by basing BIT_X to BIT_8, values as per
+ * BT-spec assigned-numbers.
+ ***************************/
+#define COD_MAJOR_MISC 0x00
+#define COD_MAJOR_COMPUTER 0x01 // BIT8
+#define COD_MAJOR_PHONE 0x02 // BIT9
+#define COD_MAJOR_LAN_NAP 0x03 // BIT8 | BIT9
+#define COD_MAJOR_AUDIO 0x04 // BIT10
+#define COD_MAJOR_PERIPHERAL 0x05 // BIT8 | BIT10
+#define COD_MAJOR_IMAGING 0x06 // BIT9 | BIT10
+#define COD_MAJOR_WEARABLE 0x07 // BIT8 | BIT9 | BIT10
+#define COD_MAJOR_TOY 0x08 // BIT11
+#define COD_MAJOR_HEALTH 0x09 // BIT8 | BIT11
+#define COD_MAJOR_UNCLASSIFIED 0x1F // BIT8 | BIT9 | BIT10 | BIT11 | BIT12
+
+/***************************
+ * service class fields
+ * Note: All values are deduced by basing BIT_X to BIT_8, values as per
+ * BT-spec assigned-numbers.
+ ***************************/
+#define COD_SERVICE_LMTD_DISCOVER 0x0020 // BIT13 (eg. 13-8 = BIT5 = 0x0020)
+#define COD_SERVICE_LE_AUDIO 0x0040 // BIT14
+#define COD_SERVICE_POSITIONING 0x0100 // BIT16
+#define COD_SERVICE_NETWORKING 0x0200 // BIT17
+#define COD_SERVICE_RENDERING 0x0400 // BIT18
+#define COD_SERVICE_CAPTURING 0x0800 // BIT19
+#define COD_SERVICE_OBJ_TRANSFER 0x1000 // BIT20
+#define COD_SERVICE_AUDIO 0x2000 // BIT21
+#define COD_SERVICE_TELEPHONY 0x4000 // BIT22
+#define COD_SERVICE_INFORMATION 0x8000 // BIT23
+
+/***************************
+ * minor device class field
+ * Note: LSB[1:0] (2 bits) is don't care for minor device class.
+ ***************************/
+/* Minor Device class field - Computer Major Class (COD_MAJOR_COMPUTER) */
+#define COD_MAJOR_COMPUTER_MINOR_UNCATEGORIZED 0x00
+#define COD_MAJOR_COMPUTER_MINOR_DESKTOP_WORKSTATION 0x04 // BIT2
+#define COD_MAJOR_COMPUTER_MINOR_SERVER_CLASS_COMPUTER 0x08 // BIT3
+#define COD_MAJOR_COMPUTER_MINOR_LAPTOP 0x0C // BIT2 | BIT3
+#define COD_MAJOR_COMPUTER_MINOR_HANDHELD_PC_PDA 0x10 // BIT4
+#define COD_MAJOR_COMPUTER_MINOR_PALM_SIZE_PC_PDA 0x14 // BIT2 | BIT4
+#define COD_MAJOR_COMPUTER_MINOR_WEARABLE_COMPUTER_WATCH_SIZE 0x18 // BIT3 | BIT4
+#define COD_MAJOR_COMPUTER_MINOR_TABLET 0x1C // BIT2 | BIT3 | BIT4
+
+/* Minor Device class field - Phone Major Class (COD_MAJOR_PHONE) */
+#define COD_MAJOR_PHONE_MINOR_UNCATEGORIZED 0x00
+#define COD_MAJOR_PHONE_MINOR_CELLULAR 0x04 // BIT2
+#define COD_MAJOR_PHONE_MINOR_CORDLESS 0x08 // BIT3
+#define COD_MAJOR_PHONE_MINOR_SMARTPHONE 0x0C // BIT2 | BIT3
+#define COD_MAJOR_PHONE_MINOR_WIRED_MODEM_OR_VOICE_GATEWAY 0x10 // BIT4
+#define COD_MAJOR_PHONE_MINOR_COMMON_ISDN_ACCESS 0x14 // BIT2 | BIT4
+
+/*
+ * Minor Device class field -
+ * LAN/Network Access Point Major Class (COD_MAJOR_LAN_NAP)
+ */
+#define COD_MAJOR_LAN_NAP_MINOR_FULLY_AVAILABLE 0x00
+#define COD_MAJOR_LAN_NAP_MINOR_1_TO_17_PER_UTILIZED 0x20 // BIT5
+#define COD_MAJOR_LAN_NAP_MINOR_17_TO_33_PER_UTILIZED 0x40 // BIT6
+#define COD_MAJOR_LAN_NAP_MINOR_33_TO_50_PER_UTILIZED 0x60 // BIT5 | BIT6
+#define COD_MAJOR_LAN_NAP_MINOR_50_TO_67_PER_UTILIZED 0x80 // BIT7
+#define COD_MAJOR_LAN_NAP_MINOR_67_TO_83_PER_UTILIZED 0xA0 // BIT5 | BIT7
+#define COD_MAJOR_LAN_NAP_MINOR_83_TO_99_PER_UTILIZED 0xC0 // BIT6 | BIT7
+#define COD_MAJOR_LAN_NAP_MINOR_NO_SERVICE_AVAILABLE 0xE0 // BIT5 | BIT6 | BIT7
+
+/* Minor Device class field - Audio/Video Major Class (COD_MAJOR_AUDIO) */
+/* 0x00 is used as unclassified for all minor device classes */
+#define COD_MINOR_UNCATEGORIZED 0x00
+#define COD_MAJOR_AUDIO_MINOR_WEARABLE_HEADSET 0x04 // BIT2
+#define COD_MAJOR_AUDIO_MINOR_CONFM_HANDSFREE 0x08 // BIT3
+#define COD_MAJOR_AUDIO_MINOR_MICROPHONE 0x10 // BIT4
+#define COD_MAJOR_AUDIO_MINOR_LOUDSPEAKER 0x14 // BIT2 | BIT4
+#define COD_MAJOR_AUDIO_MINOR_HEADPHONES 0x18 // BIT3 | BIT4
+#define COD_MAJOR_AUDIO_MINOR_PORTABLE_AUDIO 0x1C // BIT2 | BIT3 | BIT4
+#define COD_MAJOR_AUDIO_MINOR_CAR_AUDIO 0x20 // BIT5
+#define COD_MAJOR_AUDIO_MINOR_SET_TOP_BOX 0x24 // BIT2 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_HIFI_AUDIO 0x28 // BIT3 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_VCR 0x2C // BIT2 | BIT3 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_VIDEO_CAMERA 0x30 // BIT4 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_CAMCORDER 0x34 // BIT2 | BIT4 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_VIDEO_MONITOR 0x38 // BIT3 | BIT4 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_VIDEO_DISPLAY_AND_LOUDSPEAKER 0x3C // BIT2 |
+ // BIT3 | BIT4 | BIT5
+#define COD_MAJOR_AUDIO_MINOR_VIDEO_CONFERENCING 0x40 // BIT6
+#define COD_MAJOR_AUDIO_MINOR_GAMING_OR_TOY 0x48 // BIT3 | BIT6
+
+/* Minor Device class field - Peripheral Major Class (COD_MAJOR_PERIPHERAL) */
+/* Bits 6-7 independently specify mouse, keyboard, or combo mouse/keyboard */
+#define COD_MAJOR_PERIPH_MINOR_KEYBOARD 0x40 // BIT6
+#define COD_MAJOR_PERIPH_MINOR_POINTING 0x80 // BIT7
+#define COD_MAJOR_PERIPH_MINOR_KEYBOARD_AND_POINTING_DEVICE 0xC0 // BIT6 | BIT7
+
+/* Bits 2-5 OR'd with selection from bits 6-7 */
+#define COD_MAJOR_PERIPH_MINOR_JOYSTICK 0x04 // BIT2
+#define COD_MAJOR_PERIPH_MINOR_GAMEPAD 0x08 // BIT3
+#define COD_MAJOR_PERIPH_MINOR_REMOTE_CONTROL 0x0C // BIT2 | BIT3
+#define COD_MAJOR_PERIPH_MINOR_SENSING_DEVICE 0x10 // BIT4
+#define COD_MAJOR_PERIPH_MINOR_DIGITIZING_TABLET 0x14 // BIT2 | BIT4
+#define COD_MAJOR_PERIPH_MINOR_CARD_READER 0x18 /* e.g. SIM card reader, BIT3 | BIT4 */
+#define COD_MAJOR_PERIPH_MINOR_DIGITAL_PEN 0x1C // Pen, BIT2 | BIT3 | BIT4
+#define COD_MAJOR_PERIPH_MINOR_HANDHELD_SCANNER 0x20 // e.g. Barcode, RFID, BIT5
+#define COD_MAJOR_PERIPH_MINOR_HANDHELD_GESTURAL_INP_DEVICE 0x24
+ // e.g. "wand" form factor, BIT2 | BIT5
+
+/* Minor Device class field - Imaging Major Class (COD_MAJOR_IMAGING)
+ *
+ * Bits 5-7 independently specify display, camera, scanner, or printer
+ * Note: Apart from the set bit, all other bits are don't care.
+ */
+#define COD_MAJOR_IMAGING_MINOR_DISPLAY 0x10 // BIT4
+#define COD_MAJOR_IMAGING_MINOR_CAMERA 0x20 // BIT5
+#define COD_MAJOR_IMAGING_MINOR_SCANNER 0x40 // BIT6
+#define COD_MAJOR_IMAGING_MINOR_PRINTER 0x80 // BIT7
+
+/* Minor Device class field - Wearable Major Class (COD_MAJOR_WEARABLE) */
+#define COD_MAJOR_WEARABLE_MINOR_WRIST_WATCH 0x04 // BIT2
+#define COD_MAJOR_WEARABLE_MINOR_PAGER 0x08 // BIT3
+#define COD_MJAOR_WEARABLE_MINOR_JACKET 0x0C // BIT2 | BIT3
+#define COD_MAJOR_WEARABLE_MINOR_HELMET 0x10 // BIT4
+#define COD_MAJOR_WEARABLE_MINOR_GLASSES 0x14 // BIT2 | BIT4
+#define COD_MAJOR_WEARABLE_MINOR_PIN 0x18
+ // e.g. Label pin, broach, badge BIT3 | BIT4
+
+/* Minor Device class field - Toy Major Class (COD_MAJOR_TOY) */
+#define COD_MAJOR_TOY_MINOR_ROBOT 0x04 // BIT2
+#define COD_MAJOR_TOY_MINOR_VEHICLE 0x08 // BIT3
+#define COD_MAJOR_TOY_MINOR_DOLL_OR_ACTION_FIGURE 0x0C // BIT2 | BIT3
+#define COD_MAJOR_TOY_MINOR_CONTROLLER 0x10 // BIT4
+#define COD_MAJOR_TOY_MINOR_GAME 0x14 // BIT2 | BIT4
+
+/* Minor Device class field - Health Major Class (COD_MAJOR_HEALTH) */
+#define COD_MAJOR_HEALTH_MINOR_BLOOD_MONITOR 0x04 // Blood pressure monitor, BIT2
+#define COD_MAJOR_HEALTH_MINOR_THERMOMETER 0x08 // BIT3
+#define COD_MAJOR_HEALTH_MINOR_WEIGHING_SCALE 0x0C // BIT2 | BIT3
+#define COD_MAJOR_HEALTH_MINOR_GLUCOSE_METER 0x10 // BIT4
+#define COD_MAJOR_HEALTH_MINOR_PULSE_OXIMETER 0x14 // BIT2 | BIT4
+#define COD_MAJOR_HEALTH_MINOR_HEART_PULSE_MONITOR 0x18 // BIT3 | BIT4
+#define COD_MAJOR_HEALTH_MINOR_HEALTH_DATA_DISPLAY 0x1C // BIT2 | BIT3 | BIT4
+#define COD_MAJO_HEALTH_MINOR_STEP_COUNTER 0x20 // BIT5
+#define COD_MAJOR_HEALTH_MINOR_BODY_COMPOSITION_ANALYZER 0x24 // BIT2 | BIT5
+#define COD_MAJOR_HEALTH_MINOR_PEAK_FLOW_MONITOR 0x28 // BIT3 | BIT5
+#define COD_MAJOR_HEALTH_MINOR_MEDICATION_MONITOR 0x2C // BIT2 | BIT3 | BIT5
+#define COD_MAJOR_HEALTH_MINOR_KNEE_PROSTHESIS 0x30 // BIT4 | BIT5
+#define COD_MAJOR_HEALTH_MINOR_ANKLE_PROSTHESIS 0x34 // BIT3 | BIT4 | BIT5
+#define COD_MAJOR_HEALTH_MINOR_GENERIC_HEALTH_MANAGER 0x38 // BIT2 | BIT3 | BIT4 | BIT5
+#define COD_MAJOR_HEALTH_MINOR_PERSONAL_MOBILITY_DEVICE 0x3C // BIT4 | BIT5
+
/* 0x00 is used as unclassified for all minor device classes */
-#define BTM_COD_MINOR_UNCLASSIFIED 0x00
-#define BTM_COD_MINOR_WEARABLE_HEADSET 0x04
-#define BTM_COD_MINOR_CONFM_HANDSFREE 0x08
-#define BTM_COD_MINOR_CAR_AUDIO 0x20
-#define BTM_COD_MINOR_SET_TOP_BOX 0x24
+#define BTM_COD_MINOR_UNCLASSIFIED COD_MINOR_UNCATEGORIZED
+#define BTM_COD_MINOR_WEARABLE_HEADSET COD_MAJOR_AUDIO_MINOR_WEARABLE_HEADSET
+#define BTM_COD_MINOR_CONFM_HANDSFREE COD_MAJOR_AUDIO_MINOR_CONFM_HANDSFREE
+#define BTM_COD_MINOR_CAR_AUDIO COD_MAJOR_AUDIO_MINOR_CAR_AUDIO
+#define BTM_COD_MINOR_SET_TOP_BOX COD_MAJOR_AUDIO_MINOR_SET_TOP_BOX
/* minor device class field for Peripheral Major Class */
/* Bits 6-7 independently specify mouse, keyboard, or combo mouse/keyboard */
-#define BTM_COD_MINOR_KEYBOARD 0x40
-#define BTM_COD_MINOR_POINTING 0x80
+#define BTM_COD_MINOR_KEYBOARD COD_MAJOR_PERIPH_MINOR_KEYBOARD
+#define BTM_COD_MINOR_POINTING COD_MAJOR_PERIPH_MINOR_POINTING
/* Bits 2-5 OR'd with selection from bits 6-7 */
/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
-#define BTM_COD_MINOR_JOYSTICK 0x04
-#define BTM_COD_MINOR_GAMEPAD 0x08
-#define BTM_COD_MINOR_REMOTE_CONTROL 0x0C
-#define BTM_COD_MINOR_DIGITIZING_TABLET 0x14
-#define BTM_COD_MINOR_CARD_READER 0x18 /* e.g. SIM card reader */
-#define BTM_COD_MINOR_DIGITAL_PAN 0x1C
+#define BTM_COD_MINOR_JOYSTICK COD_MAJOR_PERIPH_MINOR_JOYSTICK
+#define BTM_COD_MINOR_GAMEPAD COD_MAJOR_PERIPH_MINOR_GAMEPAD
+#define BTM_COD_MINOR_REMOTE_CONTROL COD_MAJOR_PERIPH_MINOR_REMOTE_CONTROL
+#define BTM_COD_MINOR_DIGITIZING_TABLET COD_MAJOR_PERIPH_MINOR_DIGITIZING_TABLET
+#define BTM_COD_MINOR_CARD_READER COD_MAJOR_PERIPH_MINOR_CARD_READER
+#define BTM_COD_MINOR_DIGITAL_PAN COD_MAJOR_PERIPH_MINOR_DIGITAL_PEN
/* minor device class field for Imaging Major Class */
/* Bits 5-7 independently specify display, camera, scanner, or printer */
-#define BTM_COD_MINOR_DISPLAY 0x10
+#define BTM_COD_MINOR_DISPLAY COD_MAJOR_IMAGING_MINOR_DISPLAY
/* Bits 2-3 Reserved */
/* #define BTM_COD_MINOR_UNCLASSIFIED 0x00 */
/* minor device class field for Wearable Major Class */
/* Bits 2-7 meaningful */
-#define BTM_COD_MINOR_WRIST_WATCH 0x04
-#define BTM_COD_MINOR_GLASSES 0x14
+#define BTM_COD_MINOR_WRIST_WATCH COD_MAJOR_WEARABLE_MINOR_WRIST_WATCH
+#define BTM_COD_MINOR_GLASSES COD_MAJOR_WEARABLE_MINOR_GLASSES
/* minor device class field for Health Major Class */
/* Bits 2-7 meaningful */
-#define BTM_COD_MINOR_BLOOD_MONITOR 0x04
-#define BTM_COD_MINOR_THERMOMETER 0x08
-#define BTM_COD_MINOR_WEIGHING_SCALE 0x0C
-#define BTM_COD_MINOR_GLUCOSE_METER 0x10
-#define BTM_COD_MINOR_PULSE_OXIMETER 0x14
-#define BTM_COD_MINOR_HEART_PULSE_MONITOR 0x18
-#define BTM_COD_MINOR_STEP_COUNTER 0x20
+#define BTM_COD_MINOR_BLOOD_MONITOR COD_MAJOR_HEALTH_MINOR_BLOOD_MONITOR
+#define BTM_COD_MINOR_THERMOMETER COD_MAJOR_HEALTH_MINOR_THERMOMETER
+#define BTM_COD_MINOR_WEIGHING_SCALE COD_MAJOR_HEALTH_MINOR_WEIGHING_SCALE
+#define BTM_COD_MINOR_GLUCOSE_METER COD_MAJOR_HEALTH_MINOR_GLUCOSE_METER
+#define BTM_COD_MINOR_PULSE_OXIMETER COD_MAJOR_HEALTH_MINOR_PULSE_OXIMETER
+#define BTM_COD_MINOR_HEART_PULSE_MONITOR COD_MAJOR_HEALTH_MINOR_HEART_PULSE_MONITOR
+#define BTM_COD_MINOR_STEP_COUNTER COD_MAJO_HEALTH_MINOR_STEP_COUNTER
/***************************
* major device class field
***************************/
-#define BTM_COD_MAJOR_COMPUTER 0x01
-#define BTM_COD_MAJOR_PHONE 0x02
-#define BTM_COD_MAJOR_AUDIO 0x04
-#define BTM_COD_MAJOR_PERIPHERAL 0x05
-#define BTM_COD_MAJOR_IMAGING 0x06
-#define BTM_COD_MAJOR_WEARABLE 0x07
-#define BTM_COD_MAJOR_HEALTH 0x09
-#define BTM_COD_MAJOR_UNCLASSIFIED 0x1F
+#define BTM_COD_MAJOR_COMPUTER COD_MAJOR_COMPUTER
+#define BTM_COD_MAJOR_PHONE COD_MAJOR_PHONE
+#define BTM_COD_MAJOR_AUDIO COD_MAJOR_AUDIO
+#define BTM_COD_MAJOR_PERIPHERAL COD_MAJOR_PERIPHERAL
+#define BTM_COD_MAJOR_IMAGING COD_MAJOR_IMAGING
+#define BTM_COD_MAJOR_WEARABLE COD_MAJOR_WEARABLE
+#define BTM_COD_MAJOR_HEALTH COD_MAJOR_HEALTH
+#define BTM_COD_MAJOR_UNCLASSIFIED COD_MAJOR_UNCLASSIFIED
/***************************
* service class fields
***************************/
-#define BTM_COD_SERVICE_LMTD_DISCOVER 0x0020
-#define BTM_COD_SERVICE_LE_AUDIO 0x0040
-#define BTM_COD_SERVICE_POSITIONING 0x0100
-#define BTM_COD_SERVICE_NETWORKING 0x0200
-#define BTM_COD_SERVICE_RENDERING 0x0400
-#define BTM_COD_SERVICE_CAPTURING 0x0800
-#define BTM_COD_SERVICE_OBJ_TRANSFER 0x1000
-#define BTM_COD_SERVICE_AUDIO 0x2000
-#define BTM_COD_SERVICE_TELEPHONY 0x4000
-#define BTM_COD_SERVICE_INFORMATION 0x8000
+#define BTM_COD_SERVICE_LMTD_DISCOVER COD_SERVICE_LMTD_DISCOVER
+#define BTM_COD_SERVICE_LE_AUDIO COD_SERVICE_LE_AUDIO
+#define BTM_COD_SERVICE_POSITIONING COD_SERVICE_POSITIONING
+#define BTM_COD_SERVICE_NETWORKING COD_SERVICE_NETWORKING
+#define BTM_COD_SERVICE_RENDERING COD_SERVICE_RENDERING
+#define BTM_COD_SERVICE_CAPTURING COD_SERVICE_CAPTURING
+#define BTM_COD_SERVICE_OBJ_TRANSFER COD_SERVICE_OBJ_TRANSFER
+#define BTM_COD_SERVICE_AUDIO COD_SERVICE_AUDIO
+#define BTM_COD_SERVICE_TELEPHONY COD_SERVICE_TELEPHONY
+#define BTM_COD_SERVICE_INFORMATION COD_SERVICE_INFORMATION
/* the COD masks */
#define BTM_COD_MINOR_CLASS_MASK 0xFC
diff --git a/system/stack/include/btm_ble_api_types.h b/system/stack/include/btm_ble_api_types.h
index 9a1679768b..d89028d27f 100644
--- a/system/stack/include/btm_ble_api_types.h
+++ b/system/stack/include/btm_ble_api_types.h
@@ -29,6 +29,7 @@
#include "stack/include/bt_octets.h"
#include "stack/include/btm_status.h"
#include "stack/include/hci_error_code.h"
+#include "stack/include/ble_appearance.h"
#include "types/ble_address_with_type.h"
#include "types/raw_address.h"
@@ -216,60 +217,70 @@ typedef uint8_t BLE_SIGNATURE[BTM_BLE_AUTH_SIGN_LEN]; /* Device address */
#endif
/* Appearance Values Reported with BTM_BLE_AD_TYPE_APPEARANCE */
-#define BTM_BLE_APPEARANCE_UKNOWN 0x0000
-#define BTM_BLE_APPEARANCE_GENERIC_PHONE 0x0040
-#define BTM_BLE_APPEARANCE_GENERIC_COMPUTER 0x0080
-#define BTM_BLE_APPEARANCE_GENERIC_WATCH 0x00C0
-#define BTM_BLE_APPEARANCE_SPORTS_WATCH 0x00C1
-#define BTM_BLE_APPEARANCE_GENERIC_CLOCK 0x0100
-#define BTM_BLE_APPEARANCE_GENERIC_DISPLAY 0x0140
-#define BTM_BLE_APPEARANCE_GENERIC_REMOTE 0x0180
-#define BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES 0x01C0
-#define BTM_BLE_APPEARANCE_GENERIC_TAG 0x0200
-#define BTM_BLE_APPEARANCE_GENERIC_KEYRING 0x0240
-#define BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 0x0280
-#define BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 0x02C0
-#define BTM_BLE_APPEARANCE_GENERIC_THERMOMETER 0x0300
-#define BTM_BLE_APPEARANCE_THERMOMETER_EAR 0x0301
-#define BTM_BLE_APPEARANCE_GENERIC_HEART_RATE 0x0340
-#define BTM_BLE_APPEARANCE_HEART_RATE_BELT 0x0341
-#define BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 0x0380
-#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM 0x0381
-#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 0x0382
-#define BTM_BLE_APPEARANCE_GENERIC_HID 0x03C0
-#define BTM_BLE_APPEARANCE_HID_KEYBOARD 0x03C1
-#define BTM_BLE_APPEARANCE_HID_MOUSE 0x03C2
-#define BTM_BLE_APPEARANCE_HID_JOYSTICK 0x03C3
-#define BTM_BLE_APPEARANCE_HID_GAMEPAD 0x03C4
-#define BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET 0x03C5
-#define BTM_BLE_APPEARANCE_HID_CARD_READER 0x03C6
-#define BTM_BLE_APPEARANCE_HID_DIGITAL_PEN 0x03C7
-#define BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER 0x03C8
-#define BTM_BLE_APPEARANCE_GENERIC_GLUCOSE 0x0400
-#define BTM_BLE_APPEARANCE_GENERIC_WALKING 0x0440
-#define BTM_BLE_APPEARANCE_WALKING_IN_SHOE 0x0441
-#define BTM_BLE_APPEARANCE_WALKING_ON_SHOE 0x0442
-#define BTM_BLE_APPEARANCE_WALKING_ON_HIP 0x0443
-#define BTM_BLE_APPEARANCE_GENERIC_CYCLING 0x0480
-#define BTM_BLE_APPEARANCE_CYCLING_COMPUTER 0x0481
-#define BTM_BLE_APPEARANCE_CYCLING_SPEED 0x0482
-#define BTM_BLE_APPEARANCE_CYCLING_CADENCE 0x0483
-#define BTM_BLE_APPEARANCE_CYCLING_POWER 0x0484
-#define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE 0x0485
-#define BTM_BLE_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE 0x0940
-#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD 0x0941
-#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET 0x0942
-#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES 0x0943
-#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND 0x0944
-#define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 0x0C40
-#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 0x0C41
-#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST 0x0C42
-#define BTM_BLE_APPEARANCE_GENERIC_WEIGHT 0x0C80
-#define BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS 0x1440
-#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION 0x1441
-#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV 0x1442
-#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD 0x1443
-#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV 0x1444
+#define BTM_BLE_APPEARANCE_UNKNOWN BLE_APPEARANCE_UNKNOWN
+#define BTM_BLE_APPEARANCE_GENERIC_PHONE BLE_APPEARANCE_GENERIC_PHONE
+#define BTM_BLE_APPEARANCE_GENERIC_COMPUTER BLE_APPEARANCE_GENERIC_COMPUTER
+#define BTM_BLE_APPEARANCE_GENERIC_WATCH BLE_APPEARANCE_GENERIC_WATCH
+#define BTM_BLE_APPEARANCE_SPORTS_WATCH BLE_APPEARANCE_SPORTS_WATCH
+#define BTM_BLE_APPEARANCE_GENERIC_CLOCK BLE_APPEARANCE_GENERIC_CLOCK
+#define BTM_BLE_APPEARANCE_GENERIC_DISPLAY BLE_APPEARANCE_GENERIC_DISPLAY
+#define BTM_BLE_APPEARANCE_GENERIC_REMOTE BLE_APPEARANCE_GENERIC_REMOTE
+#define BTM_BLE_APPEARANCE_GENERIC_EYEGLASSES BLE_APPEARANCE_GENERIC_EYEGLASSES
+#define BTM_BLE_APPEARANCE_GENERIC_TAG BLE_APPEARANCE_GENERIC_TAG
+#define BTM_BLE_APPEARANCE_GENERIC_KEYRING BLE_APPEARANCE_GENERIC_KEYRING
+#define BTM_BLE_APPEARANCE_GENERIC_MEDIA_PLAYER BLE_APPEARANCE_GENERIC_MEDIA_PLAYER
+#define BTM_BLE_APPEARANCE_GENERIC_BARCODE_SCANNER BLE_APPEARANCE_GENERIC_BARCODE_SCANNER
+#define BTM_BLE_APPEARANCE_GENERIC_THERMOMETER BLE_APPEARANCE_GENERIC_THERMOMETER
+#define BTM_BLE_APPEARANCE_THERMOMETER_EAR BLE_APPEARANCE_THERMOMETER_EAR
+#define BTM_BLE_APPEARANCE_GENERIC_HEART_RATE BLE_APPEARANCE_GENERIC_HEART_RATE
+#define BTM_BLE_APPEARANCE_HEART_RATE_BELT BLE_APPEARANCE_HEART_RATE_BELT
+#define BTM_BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE
+#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_ARM BLE_APPEARANCE_BLOOD_PRESSURE_ARM
+#define BTM_BLE_APPEARANCE_BLOOD_PRESSURE_WRIST BLE_APPEARANCE_BLOOD_PRESSURE_WRIST
+#define BTM_BLE_APPEARANCE_GENERIC_HID BLE_APPEARANCE_GENERIC_HID
+#define BTM_BLE_APPEARANCE_HID_KEYBOARD BLE_APPEARANCE_HID_KEYBOARD
+#define BTM_BLE_APPEARANCE_HID_MOUSE BLE_APPEARANCE_HID_MOUSE
+#define BTM_BLE_APPEARANCE_HID_JOYSTICK BLE_APPEARANCE_HID_JOYSTICK
+#define BTM_BLE_APPEARANCE_HID_GAMEPAD BLE_APPEARANCE_HID_GAMEPAD
+#define BTM_BLE_APPEARANCE_HID_DIGITIZER_TABLET BLE_APPEARANCE_HID_DIGITIZER_TABLET
+#define BTM_BLE_APPEARANCE_HID_CARD_READER BLE_APPEARANCE_HID_CARD_READER
+#define BTM_BLE_APPEARANCE_HID_DIGITAL_PEN BLE_APPEARANCE_HID_DIGITAL_PEN
+#define BTM_BLE_APPEARANCE_HID_BARCODE_SCANNER BLE_APPEARANCE_HID_BARCODE_SCANNER
+#define BTM_BLE_APPEARANCE_GENERIC_GLUCOSE BLE_APPEARANCE_GENERIC_GLUCOSE
+#define BTM_BLE_APPEARANCE_GENERIC_WALKING BLE_APPEARANCE_GENERIC_WALKING
+#define BTM_BLE_APPEARANCE_WALKING_IN_SHOE BLE_APPEARANCE_WALKING_IN_SHOE
+#define BTM_BLE_APPEARANCE_WALKING_ON_SHOE BLE_APPEARANCE_WALKING_ON_SHOE
+#define BTM_BLE_APPEARANCE_WALKING_ON_HIP BLE_APPEARANCE_WALKING_ON_HIP
+#define BTM_BLE_APPEARANCE_GENERIC_CYCLING BLE_APPEARANCE_GENERIC_CYCLING
+#define BTM_BLE_APPEARANCE_CYCLING_COMPUTER BLE_APPEARANCE_CYCLING_COMPUTER
+#define BTM_BLE_APPEARANCE_CYCLING_SPEED BLE_APPEARANCE_CYCLING_SPEED
+#define BTM_BLE_APPEARANCE_CYCLING_CADENCE BLE_APPEARANCE_CYCLING_CADENCE
+#define BTM_BLE_APPEARANCE_CYCLING_POWER BLE_APPEARANCE_CYCLING_POWER
+#define BTM_BLE_APPEARANCE_CYCLING_SPEED_CADENCE BLE_APPEARANCE_CYCLING_SPEED_CADENCE
+#define BTM_BLE_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE \
+ BLE_APPEARANCE_GENERIC_WEARABLE_AUDIO_DEVICE
+#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD \
+ BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_EARBUD
+#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET \
+ BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADSET
+#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES \
+ BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_HEADPHONES
+#define BTM_BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND \
+ BLE_APPEARANCE_WEARABLE_AUDIO_DEVICE_NECK_BAND
+#define BTM_BLE_APPEARANCE_GENERIC_PULSE_OXIMETER BLE_APPEARANCE_GENERIC_PULSE_OXIMETER
+#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP
+#define BTM_BLE_APPEARANCE_PULSE_OXIMETER_WRIST BLE_APPEARANCE_PULSE_OXIMETER_WRIST
+#define BTM_BLE_APPEARANCE_GENERIC_WEIGHT BLE_APPEARANCE_GENERIC_WEIGHT
+#define BTM_BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS \
+ BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION \
+ BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV \
+ BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_AND_NAV
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD \
+ BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD
+#define BTM_BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV \
+ BLE_APPEARANCE_OUTDOOR_SPORTS_LOCATION_POD_AND_NAV
/* Structure returned with Rand/Encrypt complete callback */
typedef struct {
diff --git a/system/stack/include/btm_inq.h b/system/stack/include/btm_inq.h
index d0ae28b01b..c49912180c 100644
--- a/system/stack/include/btm_inq.h
+++ b/system/stack/include/btm_inq.h
@@ -158,3 +158,6 @@ void BTM_EnableInterlacedInquiryScan();
*
******************************************************************************/
void BTM_EnableInterlacedPageScan();
+
+void btm_inq_db_reset(void);
+void btm_clr_inq_result_flt(void);
diff --git a/system/stack/include/btm_iot_config.h b/system/stack/include/btm_iot_config.h
new file mode 100644
index 0000000000..19b575ffdf
--- /dev/null
+++ b/system/stack/include/btm_iot_config.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ * Copyright 2025 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "stack/acl/acl.h"
+
+void btm_iot_save_remote_properties(tACL_CONN* p_acl_cb);
+void btm_iot_save_remote_versions(tACL_CONN* p_acl_cb);
diff --git a/system/stack/include/sco_hci_link_interface.h b/system/stack/include/sco_hci_link_interface.h
index 5aa2cd128b..9de4eea367 100644
--- a/system/stack/include/sco_hci_link_interface.h
+++ b/system/stack/include/sco_hci_link_interface.h
@@ -33,8 +33,5 @@ void btm_sco_connection_failed(tHCI_STATUS hci_status, const RawAddress& bda, ui
tBTM_ESCO_DATA* p_esco_data);
void btm_sco_create_command_status_failed(tHCI_STATUS hci_status);
-bool btm_sco_removed(uint16_t hci_handle, tHCI_REASON reason);
-
-void btm_sco_on_disconnected(uint16_t hci_handle, tHCI_REASON reason);
void btm_sco_on_esco_connect_request(const RawAddress&, const bluetooth::hci::ClassOfDevice&);
void btm_sco_on_sco_connect_request(const RawAddress&, const bluetooth::hci::ClassOfDevice&);
diff --git a/system/stack/include/smp_status.h b/system/stack/include/smp_status.h
index 86670a5161..1d222ab419 100644
--- a/system/stack/include/smp_status.h
+++ b/system/stack/include/smp_status.h
@@ -41,25 +41,27 @@ typedef enum : uint8_t {
SMP_NUMERIC_COMPAR_FAIL = 0x0C,
SMP_BR_PARING_IN_PROGR = 0x0D,
SMP_XTRANS_DERIVE_NOT_ALLOW = 0x0E,
- SMP_MAX_FAIL_RSN_PER_SPEC = SMP_XTRANS_DERIVE_NOT_ALLOW,
+ SMP_KEY_REJECTED = 0x0F,
+ SMP_BUSY = 0x10, /*device is not ready to perform a pairing procedure*/
+ SMP_MAX_FAIL_RSN_PER_SPEC = SMP_BUSY,
/* self defined error code */
- SMP_PAIR_INTERNAL_ERR = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01), /* 0x0F */
+ SMP_PAIR_INTERNAL_ERR = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x01), /* 0x11 */
/* Unknown IO capability, unable to decide association model */
- SMP_UNKNOWN_IO_CAP = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02), /* 0x10 */
+ SMP_UNKNOWN_IO_CAP = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x02), /* 0x12 */
- SMP_BUSY = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05), /* 0x13 */
- SMP_ENC_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06), /* 0x14 */
- SMP_STARTED = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07), /* 0x15 */
- SMP_RSP_TIMEOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08), /* 0x16 */
+ SMP_IMPL_BUSY = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x05), /* 0x15 */
+ SMP_ENC_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x06), /* 0x16 */
+ SMP_STARTED = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x07), /* 0x17 */
+ SMP_RSP_TIMEOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x08), /* 0x18 */
/* Unspecified failure reason */
- SMP_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A), /* 0x18 */
+ SMP_FAIL = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0A), /* 0x1A */
- SMP_CONN_TOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B), /* 0x19 */
- SMP_SIRK_DEVICE_INVALID = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0C), /* 0x1a */
- SMP_USER_CANCELLED = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0D), /* 0x1b */
+ SMP_CONN_TOUT = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0B), /* 0x1B */
+ SMP_SIRK_DEVICE_INVALID = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0C), /* 0x1C */
+ SMP_USER_CANCELLED = (SMP_MAX_FAIL_RSN_PER_SPEC + 0x0D), /* 0x1D */
} tSMP_STATUS;
inline std::string smp_status_text(const tSMP_STATUS& status) {
@@ -79,9 +81,11 @@ inline std::string smp_status_text(const tSMP_STATUS& status) {
CASE_RETURN_TEXT(SMP_NUMERIC_COMPAR_FAIL);
CASE_RETURN_TEXT(SMP_BR_PARING_IN_PROGR);
CASE_RETURN_TEXT(SMP_XTRANS_DERIVE_NOT_ALLOW);
+ CASE_RETURN_TEXT(SMP_KEY_REJECTED);
+ CASE_RETURN_TEXT(SMP_BUSY);
CASE_RETURN_TEXT(SMP_PAIR_INTERNAL_ERR);
CASE_RETURN_TEXT(SMP_UNKNOWN_IO_CAP);
- CASE_RETURN_TEXT(SMP_BUSY);
+ CASE_RETURN_TEXT(SMP_IMPL_BUSY);
CASE_RETURN_TEXT(SMP_ENC_FAIL);
CASE_RETURN_TEXT(SMP_STARTED);
CASE_RETURN_TEXT(SMP_RSP_TIMEOUT);
diff --git a/system/stack/l2cap/l2c_link.cc b/system/stack/l2cap/l2c_link.cc
index a202c36549..9a78588840 100644
--- a/system/stack/l2cap/l2c_link.cc
+++ b/system/stack/l2cap/l2c_link.cc
@@ -34,7 +34,10 @@
#include "internal_include/bt_target.h"
#include "osi/include/allocator.h"
#include "stack/btm/btm_int_types.h"
+#include "stack/btm/btm_sco.h"
+#include "stack/btm/btm_sec.h"
#include "stack/include/acl_api.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/bt_hdr.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_status.h"
@@ -51,14 +54,6 @@ using namespace bluetooth;
extern tBTM_CB btm_cb;
-bool BTM_ReadPowerMode(const RawAddress& remote_bda, tBTM_PM_MODE* p_mode);
-tBTM_STATUS btm_sec_disconnect(uint16_t handle, tHCI_STATUS reason, std::string);
-void btm_acl_created(const RawAddress& bda, uint16_t hci_handle, uint8_t link_role,
- tBT_TRANSPORT transport);
-void btm_acl_removed(uint16_t handle);
-void btm_ble_decrement_link_topology_mask(uint8_t link_role);
-void btm_sco_acl_removed(const RawAddress* bda);
-
static void l2c_link_send_to_lower(tL2C_LCB* p_lcb, BT_HDR* p_buf, tL2C_TX_COMPLETE_CB_INFO* p_cbi);
static BT_HDR* l2cu_get_next_buffer_to_send(tL2C_LCB* p_lcb, tL2C_TX_COMPLETE_CB_INFO* p_cbi);
diff --git a/system/stack/rfcomm/port_rfc.cc b/system/stack/rfcomm/port_rfc.cc
index 14a9cb5bf0..4dc7590d96 100644
--- a/system/stack/rfcomm/port_rfc.cc
+++ b/system/stack/rfcomm/port_rfc.cc
@@ -991,7 +991,7 @@ void port_rfc_closed(tPORT* p_port, uint8_t res) {
log::warn("port_rfc_closed in OPENING state ignored");
rfc_port_timer_stop(p_port);
- p_port->rfc.sm_cb.state = RFC_STATE_CLOSED;
+ rfc_set_state(RFC_STATE_CLOSED, p_port);
if (p_mcb) {
p_mcb->port_handles[p_port->dlci] = 0;
@@ -1049,8 +1049,8 @@ void port_rfc_closed(tPORT* p_port, uint8_t res) {
p_port->p_mgmt_callback(static_cast<tPORT_RESULT>(res2), p_port->handle);
}
- p_port->rfc.sm_cb.state = RFC_STATE_CLOSED;
-
+ rfc_set_state(RFC_STATE_CLOSED, p_port);
+ p_port->rfc.sm_cb.close_reason = static_cast<tPORT_RESULT>(res);
log::info(
"RFCOMM connection closed, port_handle={}, state={}, reason={}[{}], "
"UUID=0x{:x}, bd_addr={}, is_server={}",
diff --git a/system/stack/rfcomm/rfc_int.h b/system/stack/rfcomm/rfc_int.h
index b773ee2dc2..95ca7c6d07 100644
--- a/system/stack/rfcomm/rfc_int.h
+++ b/system/stack/rfcomm/rfc_int.h
@@ -237,6 +237,7 @@ void rfc_sec_check_complete(RawAddress bd_addr, tBT_TRANSPORT transport, void* p
void rfc_inc_credit(tPORT* p_port, uint8_t credit);
void rfc_dec_credit(tPORT* p_port);
void rfc_check_send_cmd(tRFC_MCB* p_mcb, BT_HDR* p_buf);
+void rfc_set_state(tRFC_PORT_STATE state, tPORT* p_port);
/*
* Functions provided by the rfc_ts_frames.cc
diff --git a/system/stack/rfcomm/rfc_port_fsm.cc b/system/stack/rfcomm/rfc_port_fsm.cc
index be47e22617..dec82b672b 100644
--- a/system/stack/rfcomm/rfc_port_fsm.cc
+++ b/system/stack/rfcomm/rfc_port_fsm.cc
@@ -74,7 +74,9 @@ static void rfc_set_port_settings(PortSettings* port_settings, MX_FRAME* p_frame
*
******************************************************************************/
void rfc_port_sm_execute(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) {
- log::assert_that(p_port != nullptr, "NULL port event {}", event);
+ log::assert_that(p_port != nullptr, "NULL port, event {}", event);
+
+ p_port->rfc.sm_cb.last_event = event;
// logs for state RFC_STATE_OPENED handled in rfc_port_sm_opened()
if (p_port->rfc.sm_cb.state != RFC_STATE_OPENED) {
@@ -122,7 +124,7 @@ void rfc_port_sm_execute(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) {
void rfc_port_sm_state_closed(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) {
switch (event) {
case RFC_PORT_EVENT_OPEN:
- p_port->rfc.sm_cb.state = RFC_STATE_ORIG_WAIT_SEC_CHECK;
+ rfc_set_state(RFC_STATE_ORIG_WAIT_SEC_CHECK, p_port);
btm_sec_mx_access_request(p_port->rfc.p_mcb->bd_addr, true, p_port->sec_mask,
&rfc_sec_check_complete, p_port);
return;
@@ -143,7 +145,7 @@ void rfc_port_sm_state_closed(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data
rfc_timer_stop(p_port->rfc.p_mcb);
/* Open will be continued after security checks are passed */
- p_port->rfc.sm_cb.state = RFC_STATE_TERM_WAIT_SEC_CHECK;
+ rfc_set_state(RFC_STATE_TERM_WAIT_SEC_CHECK, p_port);
btm_sec_mx_access_request(p_port->rfc.p_mcb->bd_addr, false, p_port->sec_mask,
&rfc_sec_check_complete, p_port);
return;
@@ -199,7 +201,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, void* p_dat
rfc_port_timer_start(p_port, RFC_DISC_TIMEOUT);
rfc_send_disc(p_port->rfc.p_mcb, p_port->dlci);
p_port->rfc.expected_rsp = 0;
- p_port->rfc.sm_cb.state = RFC_STATE_DISC_WAIT_UA;
+ rfc_set_state(RFC_STATE_DISC_WAIT_UA, p_port);
return;
case RFC_PORT_EVENT_CLEAR:
@@ -213,7 +215,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, void* p_dat
case RFC_PORT_EVENT_UA:
rfc_port_timer_stop(p_port);
- p_port->rfc.sm_cb.state = RFC_STATE_OPENED;
+ rfc_set_state(RFC_STATE_OPENED, p_port);
if (uuid_logging_acceptlist.find(p_port->uuid) != uuid_logging_acceptlist.end()) {
// Find Channel Control Block by Channel ID
@@ -267,7 +269,7 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, tRFC_PORT_EVENT event, void* p_dat
return;
case RFC_PORT_EVENT_TIMEOUT:
- p_port->rfc.sm_cb.state = RFC_STATE_CLOSED;
+ rfc_set_state(RFC_STATE_CLOSED, p_port);
PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci, p_port->rfc.p_mcb->peer_l2cap_mtu,
RFCOMM_ERROR);
return;
@@ -334,7 +336,7 @@ void rfc_port_sm_term_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, void*
case RFC_PORT_EVENT_DISC:
btm_sec_abort_access_req(p_port->rfc.p_mcb->bd_addr);
- p_port->rfc.sm_cb.state = RFC_STATE_CLOSED;
+ rfc_set_state(RFC_STATE_CLOSED, p_port);
rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
PORT_DlcReleaseInd(p_port->rfc.p_mcb, p_port->dlci);
@@ -351,7 +353,7 @@ void rfc_port_sm_term_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, void*
}
} else {
rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
- p_port->rfc.sm_cb.state = RFC_STATE_OPENED;
+ rfc_set_state(RFC_STATE_OPENED, p_port);
if (uuid_logging_acceptlist.find(p_port->uuid) != uuid_logging_acceptlist.end()) {
// Find Channel Control Block by Channel ID
@@ -409,7 +411,7 @@ void rfc_port_sm_orig_wait_sec_check(tPORT* p_port, tRFC_PORT_EVENT event, void*
rfcomm_port_state_text(p_port->rfc.sm_cb.state), p_port->handle);
rfc_send_sabme(p_port->rfc.p_mcb, p_port->dlci);
rfc_port_timer_start(p_port, RFC_PORT_T1_TIMEOUT);
- p_port->rfc.sm_cb.state = RFC_STATE_SABME_WAIT_UA;
+ rfc_set_state(RFC_STATE_SABME_WAIT_UA, p_port);
}
return;
@@ -462,7 +464,7 @@ void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) {
rfc_port_timer_start(p_port, RFC_DISC_TIMEOUT);
rfc_send_disc(p_port->rfc.p_mcb, p_port->dlci);
p_port->rfc.expected_rsp = 0;
- p_port->rfc.sm_cb.state = RFC_STATE_DISC_WAIT_UA;
+ rfc_set_state(RFC_STATE_DISC_WAIT_UA, p_port);
return;
case RFC_PORT_EVENT_CLEAR:
@@ -510,7 +512,7 @@ void rfc_port_sm_opened(tPORT* p_port, tRFC_PORT_EVENT event, void* p_data) {
case RFC_PORT_EVENT_DISC:
log::info("RFC_PORT_EVENT_DISC bd_addr:{} port_handle:{} dlci:{} scn:{}", p_port->bd_addr,
p_port->handle, p_port->dlci, p_port->scn);
- p_port->rfc.sm_cb.state = RFC_STATE_CLOSED;
+ rfc_set_state(RFC_STATE_CLOSED, p_port);
rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
if (!fixed_queue_is_empty(p_port->rx.queue)) {
/* give a chance to upper stack to close port properly */
diff --git a/system/stack/rfcomm/rfc_port_if.cc b/system/stack/rfcomm/rfc_port_if.cc
index af6906fbb5..4fdd46059d 100644
--- a/system/stack/rfcomm/rfc_port_if.cc
+++ b/system/stack/rfcomm/rfc_port_if.cc
@@ -333,7 +333,12 @@ void RFCOMM_LineStatusReq(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t status) {
*
******************************************************************************/
void RFCOMM_DlcReleaseReq(tRFC_MCB* p_mcb, uint8_t dlci) {
- rfc_port_sm_execute(port_find_mcb_dlci_port(p_mcb, dlci), RFC_PORT_EVENT_CLOSE, nullptr);
+ tPORT* p_port = port_find_mcb_dlci_port(p_mcb, dlci);
+ if (p_port == nullptr) {
+ log::warn("Unable to find DLCI port dlci:{}", dlci);
+ return;
+ }
+ rfc_port_sm_execute(p_port, RFC_PORT_EVENT_CLOSE, nullptr);
}
/*******************************************************************************
diff --git a/system/stack/rfcomm/rfc_utils.cc b/system/stack/rfcomm/rfc_utils.cc
index 87beaaf566..d9389eda07 100644
--- a/system/stack/rfcomm/rfc_utils.cc
+++ b/system/stack/rfcomm/rfc_utils.cc
@@ -28,6 +28,7 @@
#include <cstdint>
+#include "common/time_util.h"
#include "internal_include/bt_target.h"
#include "osi/include/allocator.h"
#include "stack/include/bt_hdr.h"
@@ -341,7 +342,7 @@ void rfc_sec_check_complete(RawAddress /* bd_addr */, tBT_TRANSPORT /* transport
void rfc_port_closed(tPORT* p_port) {
tRFC_MCB* p_mcb = p_port->rfc.p_mcb;
rfc_port_timer_stop(p_port);
- p_port->rfc.sm_cb.state = RFC_STATE_CLOSED;
+ rfc_set_state(RFC_STATE_CLOSED, p_port);
/* If multiplexer channel was up mark it as down */
if (p_mcb) {
@@ -434,3 +435,28 @@ void rfc_check_send_cmd(tRFC_MCB* p_mcb, BT_HDR* p_buf) {
}
}
}
+
+/*******************************************************************************
+ *
+ * Function rfc_set_state
+ *
+ * Description This function updates the RfcommPortSm control block with a
+ * new state
+ *
+ ******************************************************************************/
+void rfc_set_state(tRFC_PORT_STATE state, tPORT* p_port) {
+ // nothing is going to change if the state doesn't change
+ if (p_port->rfc.sm_cb.state == state) {
+ log::debug("Already at state {}, no need to update", rfcomm_port_state_text(state));
+ return;
+ }
+
+ p_port->rfc.sm_cb.state_prior = p_port->rfc.sm_cb.state;
+ p_port->rfc.sm_cb.state = state;
+
+ if (state == RFC_STATE_OPENED) {
+ p_port->rfc.sm_cb.open_timestamp = bluetooth::common::time_gettimeofday_us();
+ } else if (state == RFC_STATE_CLOSED && p_port->rfc.sm_cb.open_timestamp != 0) {
+ p_port->rfc.sm_cb.close_timestamp = bluetooth::common::time_gettimeofday_us();
+ }
+}
diff --git a/system/stack/rnr/remote_name_request.cc b/system/stack/rnr/remote_name_request.cc
index bd0fcbce44..989a77bda0 100644
--- a/system/stack/rnr/remote_name_request.cc
+++ b/system/stack/rnr/remote_name_request.cc
@@ -25,15 +25,13 @@
#include "stack/btm/btm_int_types.h"
#include "stack/btm/btm_sec.h"
#include "stack/btm/security_device_record.h"
+#include "stack/include/ble_hci_link_interface.h"
#include "stack/include/btm_client_interface.h"
using namespace bluetooth;
extern tBTM_CB btm_cb;
-tBTM_STATUS btm_ble_read_remote_name(const RawAddress& remote_bda, tBTM_NAME_CMPL_CB* p_cb);
-bool btm_ble_cancel_remote_name(const RawAddress& remote_bda);
-
bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback) {
int i;
diff --git a/system/stack/smp/smp_act.cc b/system/stack/smp/smp_act.cc
index c625217c7c..fd77fabbed 100644
--- a/system/stack/smp/smp_act.cc
+++ b/system/stack/smp/smp_act.cc
@@ -23,6 +23,7 @@
#include <cstring>
+#include "bta/dm/bta_dm_sec_int.h"
#include "btif/include/btif_common.h"
#include "btif/include/core_callbacks.h"
#include "btif/include/stack_manager_t.h"
@@ -34,6 +35,7 @@
#include "stack/btm/btm_ble_sec.h"
#include "stack/btm/btm_dev.h"
#include "stack/btm/btm_sec.h"
+#include "stack/include/acl_api.h"
#include "stack/include/bt_octets.h"
#include "stack/include/bt_types.h"
#include "stack/include/btm_client_interface.h"
@@ -548,6 +550,21 @@ void smp_proc_pair_cmd(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
/* erase all keys if it is peripheral proc pairing req */
if (p_dev_rec && (p_cb->role == HCI_ROLE_PERIPHERAL)) {
+ if (com::android::bluetooth::flags::key_missing_ble_peripheral()) {
+ tBTM_SEC_DEV_REC* p_rec = btm_find_dev(p_cb->pairing_bda);
+ /* If we bonded, but not encrypted, it's a key missing - disconnect.
+ * If we are bonded, its key upgrade and ok to continue.
+ * If we are not bonded, its new device pairing and ok.
+ */
+ if (p_rec != NULL && p_rec->sec_rec.is_le_link_key_known() &&
+ !p_rec->sec_rec.is_le_device_encrypted()) {
+ log::warn("bonded unencrypted central wants to pair {}", p_cb->pairing_bda);
+ bta_dm_remote_key_missing(p_cb->pairing_bda);
+ acl_disconnect_from_handle(p_rec->ble_hci_handle, HCI_ERR_AUTH_FAILURE,
+ "bonded unencrypted central wants to pair");
+ return;
+ }
+ }
btm_sec_clear_ble_keys(p_dev_rec);
}
diff --git a/system/stack/smp/smp_api.cc b/system/stack/smp/smp_api.cc
index 0d66b0a064..a46f113aec 100644
--- a/system/stack/smp/smp_api.cc
+++ b/system/stack/smp/smp_api.cc
@@ -89,7 +89,7 @@ tSMP_STATUS SMP_Pair(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type) {
if (p_cb->state != SMP_STATE_IDLE || p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD ||
p_cb->smp_over_br) {
/* pending security on going, reject this one */
- return SMP_BUSY;
+ return SMP_IMPL_BUSY;
} else {
p_cb->flags = SMP_PAIR_FLAGS_WE_STARTED_DD;
p_cb->pairing_bda = bd_addr;
@@ -135,7 +135,7 @@ tSMP_STATUS SMP_BR_PairWith(const RawAddress& bd_addr) {
if (p_cb->state != SMP_STATE_IDLE || p_cb->smp_over_br ||
p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD) {
/* pending security on going, reject this one */
- return SMP_BUSY;
+ return SMP_IMPL_BUSY;
}
p_cb->role = HCI_ROLE_CENTRAL;
diff --git a/system/stack/smp/smp_utils.cc b/system/stack/smp/smp_utils.cc
index 81b005a78c..e5aefe3c6a 100644
--- a/system/stack/smp/smp_utils.cc
+++ b/system/stack/smp/smp_utils.cc
@@ -1231,7 +1231,7 @@ void smp_reject_unexpected_pairing_command(const RawAddress& bd_addr) {
p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
UINT8_TO_STREAM(p, SMP_OPCODE_PAIRING_FAILED);
- UINT8_TO_STREAM(p, SMP_PAIR_NOT_SUPPORT);
+ UINT8_TO_STREAM(p, SMP_BUSY);
p_buf->offset = L2CAP_MIN_OFFSET;
p_buf->len = SMP_PAIR_FAIL_SIZE;
diff --git a/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc b/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc
deleted file mode 100644
index 4f78adbb00..0000000000
--- a/system/stack/test/a2dp/a2dp_vendor_ldac_decoder_test.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2020 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 "stack/include/a2dp_vendor_ldac_decoder.h"
-
-#include <gtest/gtest.h>
-
-#include <cstdint>
-
-#include "osi/include/allocator.h"
-#include "stack/include/bt_hdr.h"
-
-namespace {
-
-uint8_t* Data(BT_HDR* packet) { return packet->data + packet->offset; }
-
-} // namespace
-
-/**
- * Test class to test selected functionality in stack/a2dp
- */
-class A2dpStackTest : public ::testing::Test {
-protected:
- BT_HDR* AllocateL2capPacket(const std::vector<uint8_t> data) const {
- auto packet = AllocatePacket(data.size());
- std::copy(data.cbegin(), data.cend(), Data(packet));
- return packet;
- }
-
-private:
- BT_HDR* AllocatePacket(size_t packet_length) const {
- BT_HDR* packet = static_cast<BT_HDR*>(osi_calloc(sizeof(BT_HDR) + packet_length));
- packet->len = packet_length;
- return packet;
- }
-};
-
-TEST_F(A2dpStackTest, DecodePacket_ZeroLength) {
- const std::vector<uint8_t> data;
- BT_HDR* p_buf = AllocateL2capPacket(data);
- ASSERT_FALSE(a2dp_vendor_ldac_decoder_decode_packet(p_buf));
- osi_free(p_buf);
-}
diff --git a/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc b/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc
index d446d808ac..d6b19a1651 100644
--- a/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc
+++ b/system/stack/test/a2dp/a2dp_vendor_ldac_unittest.cc
@@ -57,9 +57,6 @@ protected:
encoder_iface_ = const_cast<tA2DP_ENCODER_INTERFACE*>(
A2DP_VendorGetEncoderInterfaceLdac(kCodecInfoLdacCapability));
ASSERT_NE(encoder_iface_, nullptr);
- decoder_iface_ = const_cast<tA2DP_DECODER_INTERFACE*>(
- A2DP_VendorGetDecoderInterfaceLdac(kCodecInfoLdacCapability));
- ASSERT_NE(decoder_iface_, nullptr);
}
void TearDown() override {
@@ -69,22 +66,15 @@ protected:
if (encoder_iface_ != nullptr) {
encoder_iface_->encoder_cleanup();
}
- if (decoder_iface_ != nullptr) {
- decoder_iface_->decoder_cleanup();
- }
}
// NOTE: Make a super func for all codecs
void SetCodecConfig() {
uint8_t source_codec_info_result[AVDT_CODEC_SIZE];
- btav_a2dp_codec_index_t peer_codec_index;
a2dp_codecs_ = new A2dpCodecs(std::vector<btav_a2dp_codec_config_t>());
ASSERT_TRUE(a2dp_codecs_->init());
- peer_codec_index = A2DP_SinkCodecIndex(kCodecInfoLdacCapability);
- ASSERT_NE(peer_codec_index, BTAV_A2DP_CODEC_INDEX_MAX);
- ASSERT_EQ(peer_codec_index, BTAV_A2DP_CODEC_INDEX_SINK_LDAC);
source_codec_config_ = a2dp_codecs_->findSourceCodecConfig(kCodecInfoLdacCapability);
ASSERT_NE(source_codec_config_, nullptr);
ASSERT_TRUE(a2dp_codecs_->setCodecConfig(kCodecInfoLdacCapability, true,
@@ -103,7 +93,6 @@ protected:
encoder_iface_->encoder_init(&peer_params, source_codec_config_, read_cb, enqueue_cb);
}
- void InitializeDecoder(decoded_data_callback_t data_cb) { decoder_iface_->decoder_init(data_cb); }
BT_HDR* AllocateL2capPacket(const std::vector<uint8_t> data) const {
auto packet = AllocatePacket(data.size());
std::copy(data.cbegin(), data.cend(), Data(packet));
@@ -118,7 +107,6 @@ protected:
A2dpCodecConfig* source_codec_config_;
A2dpCodecs* a2dp_codecs_;
tA2DP_ENCODER_INTERFACE* encoder_iface_;
- tA2DP_DECODER_INTERFACE* decoder_iface_;
};
TEST_F(A2dpLdacTest, a2dp_source_read_underflow) {
diff --git a/system/stack/test/a2dp/misc_fake.cc b/system/stack/test/a2dp/misc_fake.cc
deleted file mode 100644
index ee82394629..0000000000
--- a/system/stack/test/a2dp/misc_fake.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2020 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 "stack/include/a2dp_vendor_ldac.h"
-
-int A2DP_VendorGetTrackSampleRateLdac(const uint8_t* /*p_codec_info*/) { return 0; }
-int A2DP_VendorGetTrackBitsPerSampleLdac(const uint8_t* /*p_codec_info*/) { return 0; }
-int A2DP_VendorGetChannelModeCodeLdac(const uint8_t* /*p_codec_info*/) { return 0; }
diff --git a/system/stack/test/btm/stack_btm_dm_inq_db_test.cc b/system/stack/test/btm/stack_btm_dm_inq_db_test.cc
index 7f5e27f26f..7fc971a5c3 100644
--- a/system/stack/test/btm/stack_btm_dm_inq_db_test.cc
+++ b/system/stack/test/btm/stack_btm_dm_inq_db_test.cc
@@ -23,6 +23,7 @@
#include "stack/btm/btm_int_types.h"
#include "stack/btm/neighbor_inquiry.h"
+#include "stack/include/btm_inq.h"
#include "stack/include/inq_hci_link_interface.h"
#include "test/common/mock_functions.h"
#include "test/fake/fake_looper.h"
@@ -32,8 +33,6 @@
#include "test/mock/mock_osi_thread.h"
extern tBTM_CB btm_cb;
-extern void btm_init_inq_result_flt(void);
-extern void btm_clr_inq_result_flt(void);
namespace {
constexpr size_t kNumberOfThreads = 8;
diff --git a/system/stack/test/btm/stack_btm_sec_test.cc b/system/stack/test/btm/stack_btm_sec_test.cc
index 3bfac8572d..58317afc29 100644
--- a/system/stack/test/btm/stack_btm_sec_test.cc
+++ b/system/stack/test/btm/stack_btm_sec_test.cc
@@ -48,17 +48,7 @@ const uint8_t kBdName[] = "kBdName";
constexpr char kTimeFormat[] = "%Y-%m-%d %H:%M:%S";
} // namespace
-namespace bluetooth {
-namespace testing {
-namespace legacy {
-
-void wipe_secrets_and_remove(tBTM_SEC_DEV_REC* p_dev_rec);
-
-} // namespace legacy
-} // namespace testing
-} // namespace bluetooth
-
-using bluetooth::testing::legacy::wipe_secrets_and_remove;
+using bluetooth::legacy::testing::wipe_secrets_and_remove;
constexpr size_t kBtmSecMaxDeviceRecords = static_cast<size_t>(BTM_SEC_MAX_DEVICE_RECORDS + 1);
diff --git a/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h b/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h
index 87c9a55cc0..888fa563f6 100644
--- a/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h
+++ b/system/stack/test/fuzzers/a2dp/codec/a2dpCodecHelperFunctions.h
@@ -34,7 +34,6 @@ static const std::vector<btav_a2dp_codec_index_t> CODEC_INDEX_ENUM_VALS = {
BTAV_A2DP_CODEC_INDEX_SINK_MIN,
BTAV_A2DP_CODEC_INDEX_SINK_SBC,
BTAV_A2DP_CODEC_INDEX_SINK_AAC,
- BTAV_A2DP_CODEC_INDEX_SINK_LDAC,
BTAV_A2DP_CODEC_INDEX_SINK_MAX,
BTAV_A2DP_CODEC_INDEX_MIN,
BTAV_A2DP_CODEC_INDEX_MAX};
diff --git a/system/stack/test/stack_a2dp_test.cc b/system/stack/test/stack_a2dp_test.cc
index ee4d56ce54..e54a6be472 100644
--- a/system/stack/test/stack_a2dp_test.cc
+++ b/system/stack/test/stack_a2dp_test.cc
@@ -244,20 +244,6 @@ const uint8_t codec_info_non_a2dp_fake[AVDT_CODEC_SIZE] = {
10 // Unused
};
-static const char* APTX_ENCODER_LIB_NAME = "libaptX_encoder.so";
-static const char* APTX_HD_ENCODER_LIB_NAME = "libaptXHD_encoder.so";
-static const char* LDAC_ENCODER_LIB_NAME = "libldacBT_enc.so";
-static const char* LDAC_DECODER_LIB_NAME = "libldacBT_dec.so";
-
-static bool has_shared_library(const char* name) {
- void* lib_handle = dlopen(name, RTLD_NOW);
- if (lib_handle != nullptr) {
- dlclose(lib_handle);
- return true;
- }
- return false;
-}
-
} // namespace
class StackA2dpTest : public ::testing::Test {
@@ -270,46 +256,22 @@ protected:
bool supported = false;
switch (codec_index) {
case BTAV_A2DP_CODEC_INDEX_SOURCE_SBC:
- supported = true;
- break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_AAC:
- supported = true;
- break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX:
- // Codec aptX is supported only if the device has the corresponding
- // shared library installed.
- supported = has_shared_library(APTX_ENCODER_LIB_NAME);
- break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_APTX_HD:
- // Codec aptX-HD is supported only if the device has the corresponding
- // shared library installed.
- supported = has_shared_library(APTX_HD_ENCODER_LIB_NAME);
- break;
case BTAV_A2DP_CODEC_INDEX_SOURCE_LDAC:
- // Codec LDAC is supported only if the device has the corresponding
- // shared library installed.
- supported = has_shared_library(LDAC_ENCODER_LIB_NAME);
- break;
- case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
supported = true;
break;
+ case BTAV_A2DP_CODEC_INDEX_SINK_SBC:
case BTAV_A2DP_CODEC_INDEX_SINK_AAC:
- supported = true;
- break;
- case BTAV_A2DP_CODEC_INDEX_SINK_LDAC:
- // Codec LDAC is supported only if the device has the corresponding
- // shared library installed.
- supported = has_shared_library(LDAC_DECODER_LIB_NAME);
- break;
- case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
- break;
- case BTAV_A2DP_CODEC_INDEX_SOURCE_OPUS:
case BTAV_A2DP_CODEC_INDEX_SINK_OPUS:
supported = true;
break;
case BTAV_A2DP_CODEC_INDEX_MAX:
case BTAV_A2DP_CODEC_INDEX_SOURCE_MAX:
case BTAV_A2DP_CODEC_INDEX_SINK_MAX:
+ case BTAV_A2DP_CODEC_INDEX_SOURCE_LC3:
// Needed to avoid using "default:" case so we can capture when
// a new codec is added, and it can be included here.
break;
diff --git a/system/stack/test/stack_smp_test.cc b/system/stack/test/stack_smp_test.cc
index 41d61e738b..8f020ae1c5 100644
--- a/system/stack/test/stack_smp_test.cc
+++ b/system/stack/test/stack_smp_test.cc
@@ -375,11 +375,13 @@ TEST(SmpStatusText, smp_status_text) {
std::make_pair(SMP_NUMERIC_COMPAR_FAIL, "SMP_NUMERIC_COMPAR_FAIL"),
std::make_pair(SMP_BR_PARING_IN_PROGR, "SMP_BR_PARING_IN_PROGR"),
std::make_pair(SMP_XTRANS_DERIVE_NOT_ALLOW, "SMP_XTRANS_DERIVE_NOT_ALLOW"),
+ std::make_pair(SMP_KEY_REJECTED, "SMP_KEY_REJECTED"),
+ std::make_pair(SMP_BUSY, "SMP_BUSY"),
std::make_pair(SMP_MAX_FAIL_RSN_PER_SPEC,
- "SMP_XTRANS_DERIVE_NOT_ALLOW"), // NOTE: Dup
+ "SMP_BUSY"), // NOTE: Dup
std::make_pair(SMP_PAIR_INTERNAL_ERR, "SMP_PAIR_INTERNAL_ERR"),
std::make_pair(SMP_UNKNOWN_IO_CAP, "SMP_UNKNOWN_IO_CAP"),
- std::make_pair(SMP_BUSY, "SMP_BUSY"),
+ std::make_pair(SMP_IMPL_BUSY, "SMP_IMPL_BUSY"),
std::make_pair(SMP_ENC_FAIL, "SMP_ENC_FAIL"),
std::make_pair(SMP_STARTED, "SMP_STARTED"),
std::make_pair(SMP_RSP_TIMEOUT, "SMP_RSP_TIMEOUT"),
diff --git a/system/test/headless/property.cc b/system/test/headless/property.cc
index fe6e21f1ed..2b5df50ff2 100644
--- a/system/test/headless/property.cc
+++ b/system/test/headless/property.cc
@@ -99,6 +99,10 @@ std::map<::bt_property_type_t,
return new headless::property::void_t(data, len,
BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP);
}},
+ {BT_PROPERTY_UUIDS_LE,
+ [](const uint8_t* data, const size_t len) -> headless::bt_property_t* {
+ return new headless::property::uuid_t(data, len);
+ }},
};
} // namespace
diff --git a/system/test/headless/property.h b/system/test/headless/property.h
index 6af17a244f..1113495f24 100644
--- a/system/test/headless/property.h
+++ b/system/test/headless/property.h
@@ -52,6 +52,7 @@ inline std::string bt_property_type_text(const ::bt_property_type_t type) {
CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_MODEL_NUM);
CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP);
CASE_RETURN_TEXT(BT_PROPERTY_REMOTE_ADDR_TYPE);
+ CASE_RETURN_TEXT(BT_PROPERTY_UUIDS_LE);
CASE_RETURN_TEXT(BT_PROPERTY_RESERVED_0x14);
default:
RETURN_UNKNOWN_TYPE_STRING(::bt_property_type_t, type);
diff --git a/system/test/mock/mock_stack_btm_ble.cc b/system/test/mock/mock_stack_btm_ble.cc
index 7e1a2154b9..620b9e252c 100644
--- a/system/test/mock/mock_stack_btm_ble.cc
+++ b/system/test/mock/mock_stack_btm_ble.cc
@@ -81,8 +81,6 @@ struct btm_ble_update_sec_key_size btm_ble_update_sec_key_size;
struct btm_get_local_div btm_get_local_div;
struct btm_proc_smp_cback btm_proc_smp_cback;
struct btm_sec_save_le_key btm_sec_save_le_key;
-struct doNothing doNothing;
-struct read_phy_cb read_phy_cb;
} // namespace stack_btm_ble
} // namespace mock
@@ -292,15 +290,6 @@ void btm_sec_save_le_key(const RawAddress& bd_addr, tBTM_LE_KEY_TYPE key_type,
inc_func_call_count(__func__);
test::mock::stack_btm_ble::btm_sec_save_le_key(bd_addr, key_type, p_keys, pass_to_application);
}
-void doNothing(uint8_t* data, uint16_t len) {
- inc_func_call_count(__func__);
- test::mock::stack_btm_ble::doNothing(data, len);
-}
-void read_phy_cb(base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
- uint8_t* data, uint16_t len) {
- inc_func_call_count(__func__);
- test::mock::stack_btm_ble::read_phy_cb(cb, data, len);
-}
// Mocked functions complete
// END mockcify generation
diff --git a/system/test/mock/mock_stack_btm_ble.h b/system/test/mock/mock_stack_btm_ble.h
index 1133b60b4c..9c1b14d014 100644
--- a/system/test/mock/mock_stack_btm_ble.h
+++ b/system/test/mock/mock_stack_btm_ble.h
@@ -545,32 +545,6 @@ struct btm_sec_save_le_key {
};
extern struct btm_sec_save_le_key btm_sec_save_le_key;
-// Name: doNothing
-// Params: uint8_t* data, uint16_t len
-// Return: void
-struct doNothing {
- std::function<void(uint8_t* data, uint16_t len)> body{
- [](uint8_t* /* data */, uint16_t /* len */) {}};
- void operator()(uint8_t* data, uint16_t len) { body(data, len); }
-};
-extern struct doNothing doNothing;
-
-// Name: read_phy_cb
-// Params: base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status
-// Return: void
-struct read_phy_cb {
- std::function<void(base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> callback,
- uint8_t* data, uint16_t len)>
- body{[](base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)>
- /* callback */,
- uint8_t* /* data */, uint16_t /* len */) {}};
- void operator()(base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> callback,
- uint8_t* data, uint16_t len) {
- body(callback, data, len);
- }
-};
-extern struct read_phy_cb read_phy_cb;
-
} // namespace stack_btm_ble
} // namespace mock
} // namespace test
diff --git a/system/test/mock/mock_stack_btm_ble_gap.cc b/system/test/mock/mock_stack_btm_ble_gap.cc
index 93e134c4a8..de8731ef54 100644
--- a/system/test/mock/mock_stack_btm_ble_gap.cc
+++ b/system/test/mock/mock_stack_btm_ble_gap.cc
@@ -46,10 +46,6 @@ using SyncReportCb =
using SyncLostCb = base::Callback<void(uint16_t /*sync_handle*/)>;
using SyncTransferCb = base::Callback<void(uint8_t /*status*/, RawAddress)>;
-bool ble_vnd_is_included() {
- inc_func_call_count(__func__);
- return false;
-}
bool BTM_BleConfigPrivacy(bool /* privacy_mode */) {
inc_func_call_count(__func__);
return false;
@@ -58,9 +54,9 @@ bool BTM_BleLocalPrivacyEnabled(void) {
inc_func_call_count(__func__);
return false;
}
-bool btm_ble_read_remote_cod(const RawAddress& /* remote_bda */) {
+tBTM_STATUS btm_ble_read_remote_cod(const RawAddress& /* remote_bda */) {
inc_func_call_count(__func__);
- return false;
+ return tBTM_STATUS::BTM_SUCCESS;
}
bool btm_ble_cancel_remote_name(const RawAddress& /* remote_bda */) {
inc_func_call_count(__func__);
@@ -144,18 +140,7 @@ void btm_ble_process_adv_pkt_cont_for_inquiry(
void btm_ble_read_remote_features_complete(uint8_t* /* p */, uint8_t /* length */) {
inc_func_call_count(__func__);
}
-void btm_ble_read_remote_name_cmpl(bool /* status */, const RawAddress& /* bda */,
- uint16_t /* length */, char* /* p_name */) {
- inc_func_call_count(__func__);
-}
-void btm_ble_set_adv_flag(uint16_t /* connect_mode */, uint16_t /* disc_mode */) {
- inc_func_call_count(__func__);
-}
void btm_ble_stop_inquiry(void) { inc_func_call_count(__func__); }
-void btm_ble_update_dmt_flag_bits(uint8_t* /* adv_flag_value */, const uint16_t /* connect_mode */,
- const uint16_t /* disc_mode */) {
- inc_func_call_count(__func__);
-}
void btm_ble_update_mode_operation(uint8_t /* link_role */, const RawAddress* /* bd_addr */,
tHCI_STATUS /* status */) {
inc_func_call_count(__func__);
diff --git a/system/test/mock/mock_stack_btm_devctl.cc b/system/test/mock/mock_stack_btm_devctl.cc
index fc27fab6db..da8d8b2053 100644
--- a/system/test/mock/mock_stack_btm_devctl.cc
+++ b/system/test/mock/mock_stack_btm_devctl.cc
@@ -32,14 +32,6 @@
// TODO(b/369381361) Enfore -Wmissing-prototypes
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-namespace test {
-namespace mock {
-namespace stack_btm_devctl {
-
-}
-} // namespace mock
-} // namespace test
-
tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* /* bd_addr */, tBTM_CMPL_CB* /* p_cb */) {
inc_func_call_count(__func__);
return tBTM_STATUS::BTM_SUCCESS;
@@ -56,5 +48,3 @@ void BTM_db_reset(void) { inc_func_call_count(__func__); }
void btm_delete_stored_link_key_complete(uint8_t* /* p */, uint16_t /* evt_len */) {
inc_func_call_count(__func__);
}
-void btm_dev_free() { inc_func_call_count(__func__); }
-void btm_dev_init() { inc_func_call_count(__func__); }
diff --git a/system/test/mock/mock_stack_btm_inq.cc b/system/test/mock/mock_stack_btm_inq.cc
index b137827eb9..ed99d05e6f 100644
--- a/system/test/mock/mock_stack_btm_inq.cc
+++ b/system/test/mock/mock_stack_btm_inq.cc
@@ -48,7 +48,6 @@ struct BTM_SetConnectability BTM_SetConnectability;
struct BTM_SetDiscoverability BTM_SetDiscoverability;
struct BTM_SetInquiryMode BTM_SetInquiryMode;
struct BTM_StartInquiry BTM_StartInquiry;
-struct btm_clear_all_pending_le_entry btm_clear_all_pending_le_entry;
struct btm_clr_inq_db btm_clr_inq_db;
struct btm_clr_inq_result_flt btm_clr_inq_result_flt;
struct btm_inq_db_find btm_inq_db_find;
@@ -56,8 +55,6 @@ struct btm_inq_db_new btm_inq_db_new;
struct btm_inq_db_reset btm_inq_db_reset;
struct btm_inq_find_bdaddr btm_inq_find_bdaddr;
struct btm_process_inq_complete btm_process_inq_complete;
-struct btm_set_eir_uuid btm_set_eir_uuid;
-struct btm_sort_inq_result btm_sort_inq_result;
} // namespace stack_btm_inq
} // namespace mock
@@ -119,10 +116,6 @@ tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb, tBTM_CMPL_CB* p_
inc_func_call_count(__func__);
return test::mock::stack_btm_inq::BTM_StartInquiry(p_results_cb, p_cmpl_cb);
}
-void btm_clear_all_pending_le_entry(void) {
- inc_func_call_count(__func__);
- test::mock::stack_btm_inq::btm_clear_all_pending_le_entry();
-}
void btm_clr_inq_db(const RawAddress* p_bda) {
inc_func_call_count(__func__);
test::mock::stack_btm_inq::btm_clr_inq_db(p_bda);
@@ -151,13 +144,5 @@ void btm_process_inq_complete(tHCI_STATUS status, uint8_t mode) {
inc_func_call_count(__func__);
test::mock::stack_btm_inq::btm_process_inq_complete(status, mode);
}
-void btm_set_eir_uuid(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) {
- inc_func_call_count(__func__);
- test::mock::stack_btm_inq::btm_set_eir_uuid(p_eir, p_results);
-}
-void btm_sort_inq_result(void) {
- inc_func_call_count(__func__);
- test::mock::stack_btm_inq::btm_sort_inq_result();
-}
// Mocked functions complete
// END mockcify generation
diff --git a/system/test/mock/mock_stack_btm_inq.h b/system/test/mock/mock_stack_btm_inq.h
index d89dd534c2..4c0acd08a4 100644
--- a/system/test/mock/mock_stack_btm_inq.h
+++ b/system/test/mock/mock_stack_btm_inq.h
@@ -143,15 +143,6 @@ struct BTM_StartInquiry {
};
extern struct BTM_StartInquiry BTM_StartInquiry;
-// Name: btm_clear_all_pending_le_entry
-// Params: void
-// Return: void
-struct btm_clear_all_pending_le_entry {
- std::function<void(void)> body{[](void) {}};
- void operator()(void) { body(); }
-};
-extern struct btm_clear_all_pending_le_entry btm_clear_all_pending_le_entry;
-
// Name: btm_clr_inq_db
// Params: const RawAddress* p_bda
// Return: void
@@ -222,25 +213,6 @@ struct btm_process_inq_complete {
};
extern struct btm_process_inq_complete btm_process_inq_complete;
-// Name: btm_set_eir_uuid
-// Params: const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results
-// Return: void
-struct btm_set_eir_uuid {
- std::function<void(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results)> body{
- [](const uint8_t* /* p_eir */, tBTM_INQ_RESULTS* /* p_results */) {}};
- void operator()(const uint8_t* p_eir, tBTM_INQ_RESULTS* p_results) { body(p_eir, p_results); }
-};
-extern struct btm_set_eir_uuid btm_set_eir_uuid;
-
-// Name: btm_sort_inq_result
-// Params: void
-// Return: void
-struct btm_sort_inq_result {
- std::function<void(void)> body{[](void) {}};
- void operator()(void) { body(); }
-};
-extern struct btm_sort_inq_result btm_sort_inq_result;
-
} // namespace stack_btm_inq
} // namespace mock
} // namespace test
diff --git a/system/test/mock/mock_stack_btm_sco.cc b/system/test/mock/mock_stack_btm_sco.cc
index 949e635b09..0128227349 100644
--- a/system/test/mock/mock_stack_btm_sco.cc
+++ b/system/test/mock/mock_stack_btm_sco.cc
@@ -33,10 +33,6 @@
// TODO(b/369381361) Enfore -Wmissing-prototypes
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-bool btm_sco_removed(uint16_t /* hci_handle */, tHCI_REASON /* reason */) {
- inc_func_call_count(__func__);
- return false;
-}
const RawAddress* BTM_ReadScoBdAddr(uint16_t /* sco_inx */) {
inc_func_call_count(__func__);
return nullptr;
@@ -91,9 +87,6 @@ void btm_sco_on_sco_connect_request(const RawAddress& /* bda */,
const bluetooth::hci::ClassOfDevice& /* cod */) {
inc_func_call_count(__func__);
}
-void btm_sco_on_disconnected(uint16_t /* hci_handle */, tHCI_REASON /* reason */) {
- inc_func_call_count(__func__);
-}
bool btm_peer_supports_esco_2m_phy(RawAddress /* bd_addr */) {
inc_func_call_count(__func__);
return true;
diff --git a/system/test/mock/mock_stack_btm_sec.cc b/system/test/mock/mock_stack_btm_sec.cc
index cdf4b97df6..4ca3189b30 100644
--- a/system/test/mock/mock_stack_btm_sec.cc
+++ b/system/test/mock/mock_stack_btm_sec.cc
@@ -64,7 +64,6 @@ struct BTM_SetEncryption BTM_SetEncryption;
struct BTM_SetPinType BTM_SetPinType;
struct BTM_SetSecurityLevel BTM_SetSecurityLevel;
struct BTM_update_version_info BTM_update_version_info;
-struct NotifyBondingCanceled NotifyBondingCanceled;
struct btm_create_conn_cancel_complete btm_create_conn_cancel_complete;
struct btm_get_dev_class btm_get_dev_class;
struct btm_io_capabilities_req btm_io_capabilities_req;
@@ -235,10 +234,6 @@ void BTM_update_version_info(const RawAddress& bd_addr,
inc_func_call_count(__func__);
test::mock::stack_btm_sec::BTM_update_version_info(bd_addr, remote_version_info);
}
-void NotifyBondingCanceled(tBTM_STATUS btm_status) {
- inc_func_call_count(__func__);
- test::mock::stack_btm_sec::NotifyBondingCanceled(btm_status);
-}
void btm_create_conn_cancel_complete(uint8_t status, const RawAddress bd_addr) {
inc_func_call_count(__func__);
test::mock::stack_btm_sec::btm_create_conn_cancel_complete(status, bd_addr);
diff --git a/system/test/mock/mock_stack_btm_sec.h b/system/test/mock/mock_stack_btm_sec.h
index c40e57c593..688ab5dca1 100644
--- a/system/test/mock/mock_stack_btm_sec.h
+++ b/system/test/mock/mock_stack_btm_sec.h
@@ -331,15 +331,6 @@ struct BTM_update_version_info {
};
extern struct BTM_update_version_info BTM_update_version_info;
-// Name: NotifyBondingCanceled
-// Params: tBTM_STATUS btm_status
-// Return: void
-struct NotifyBondingCanceled {
- std::function<void(tBTM_STATUS btm_status)> body{[](tBTM_STATUS /* btm_status */) {}};
- void operator()(tBTM_STATUS btm_status) { body(btm_status); }
-};
-extern struct NotifyBondingCanceled NotifyBondingCanceled;
-
// Name: btm_create_conn_cancel_complete
// Params: uint8_t status, RawAddress bd_addr
// Return: void
diff --git a/tools/rootcanal/model/controller/controller_properties.cc b/tools/rootcanal/model/controller/controller_properties.cc
index 26718a9747..3f6c918bfe 100644
--- a/tools/rootcanal/model/controller/controller_properties.cc
+++ b/tools/rootcanal/model/controller/controller_properties.cc
@@ -1743,6 +1743,40 @@ ControllerProperties::ControllerProperties(rootcanal::configuration::Controller
le_supported_states = 0x3ffffffffff;
break;
+ case ControllerPreset::INTEL_BE200:
+ // Configuration extracted with the helper script controller_info.py
+ supports_csr_vendor_command = true;
+ br_supported = true;
+ le_supported = true;
+ hci_version = bluetooth::hci::HciVersion::V_5_4;
+ hci_subversion = 0x4363;
+ lmp_version = bluetooth::hci::LmpVersion::V_5_4;
+ lmp_subversion = 0x4363;
+ company_identifier = 0x2;
+ supported_commands = std::array<uint8_t, 64>{
+ 0xbf, 0xff, 0xfb, 0x03, 0xcc, 0xff, 0x0f, 0xff, 0xbf, 0xff, 0xfc, 0x1f, 0xf2,
+ 0x0f, 0xe8, 0xfe, 0x3f, 0xf7, 0x8f, 0xff, 0x1c, 0x00, 0x04, 0x00, 0x61, 0xf7,
+ 0xff, 0xff, 0x7f, 0x38, 0x00, 0x00, 0xfe, 0xf0, 0xff, 0xff, 0xff, 0xe3, 0x80,
+ 0x07, 0x00, 0xe8, 0x1f, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ lmp_features = std::array<uint64_t, 3>{0x877bffdbfe0ffebf, 0x0, 0x300};
+ acl_data_packet_length = 1021;
+ total_num_acl_data_packets = 4;
+ sco_data_packet_length = 96;
+ total_num_sco_data_packets = 6;
+ num_supported_iac = 2;
+ le_features = 0x80059ff;
+ le_acl_data_packet_length = 251;
+ total_num_le_acl_data_packets = 3;
+ le_filter_accept_list_size = 25;
+ le_resolving_list_size = 25;
+ le_supported_states = 0x3ffffffffff;
+ le_max_advertising_data_length = 160;
+ le_num_supported_advertising_sets = 12;
+ le_periodic_advertiser_list_size = 12;
+ break;
+
default:
break;
}
diff --git a/tools/rootcanal/model/controller/dual_mode_controller.cc b/tools/rootcanal/model/controller/dual_mode_controller.cc
index 15f788b438..c7b5d0bbe2 100644
--- a/tools/rootcanal/model/controller/dual_mode_controller.cc
+++ b/tools/rootcanal/model/controller/dual_mode_controller.cc
@@ -3290,6 +3290,11 @@ void DualModeController::WriteLoopbackMode(CommandView command) {
ErrorCode::SUCCESS));
}
+void DualModeController::IntelDdcConfigWrite(CommandView /*command*/) {
+ send_event_(bluetooth::hci::CommandCompleteBuilder::Create(kNumCommandPackets, OpCode::INTEL_DDC_CONFIG_WRITE,
+ std::vector<uint8_t> { static_cast<uint8_t>(ErrorCode::SUCCESS) }));
+}
+
// Note: the list does not contain all defined opcodes.
// Notable exceptions:
// - Vendor commands
@@ -4274,6 +4279,8 @@ const std::unordered_map<OpCode, DualModeController::CommandHandler>
{OpCode::LE_GET_CONTROLLER_ACTIVITY_ENERGY_INFO,
&DualModeController::LeGetControllerActivityEnergyInfo},
{OpCode::LE_EX_SET_SCAN_PARAMETERS, &DualModeController::LeExSetScanParameters},
- {OpCode::GET_CONTROLLER_DEBUG_INFO, &DualModeController::GetControllerDebugInfo}};
+ {OpCode::GET_CONTROLLER_DEBUG_INFO, &DualModeController::GetControllerDebugInfo},
+ {OpCode::INTEL_DDC_CONFIG_WRITE, &DualModeController::IntelDdcConfigWrite},
+ };
} // namespace rootcanal
diff --git a/tools/rootcanal/model/controller/dual_mode_controller.h b/tools/rootcanal/model/controller/dual_mode_controller.h
index d0394a7bfd..c5574bda85 100644
--- a/tools/rootcanal/model/controller/dual_mode_controller.h
+++ b/tools/rootcanal/model/controller/dual_mode_controller.h
@@ -525,6 +525,7 @@ public:
void LeGetControllerActivityEnergyInfo(CommandView command);
void LeExSetScanParameters(CommandView command);
void GetControllerDebugInfo(CommandView command);
+ void IntelDdcConfigWrite(CommandView command);
// CSR vendor command.
// Implement the command specific to the CSR controller
diff --git a/tools/rootcanal/model/setup/test_command_handler.cc b/tools/rootcanal/model/setup/test_command_handler.cc
index 93315ae16e..59071842a5 100644
--- a/tools/rootcanal/model/setup/test_command_handler.cc
+++ b/tools/rootcanal/model/setup/test_command_handler.cc
@@ -246,6 +246,8 @@ void TestCommandHandler::SetDeviceConfiguration(const vector<std::string>& args)
preset = rootcanal::configuration::ControllerPreset::LAIRD_BL654;
} else if (args[1] == "csr_rck_pts_dongle") {
preset = rootcanal::configuration::ControllerPreset::CSR_RCK_PTS_DONGLE;
+ } else if (args[1] == "intel_be200") {
+ preset = rootcanal::configuration::ControllerPreset::INTEL_BE200;
} else {
response_string_ = "TestCommandHandler 'set_device_configuration' invalid configuration preset";
send_response_(response_string_);
diff --git a/tools/rootcanal/packets/hci_packets.pdl b/tools/rootcanal/packets/hci_packets.pdl
index 23abb93b29..8f3d3c1588 100644
--- a/tools/rootcanal/packets/hci_packets.pdl
+++ b/tools/rootcanal/packets/hci_packets.pdl
@@ -400,6 +400,7 @@ enum OpCode : 16 {
// VENDOR_SPECIFIC
// MSFT_OPCODE_xxxx below is needed for the tests.
MSFT_OPCODE_INTEL = 0xFC1E,
+ INTEL_DDC_CONFIG_WRITE = 0xFC8B,
LE_GET_VENDOR_CAPABILITIES = 0xFD53,
LE_BATCH_SCAN = 0xFD56,
LE_APCF = 0xFD57,
diff --git a/tools/rootcanal/proto/rootcanal/configuration.proto b/tools/rootcanal/proto/rootcanal/configuration.proto
index 0b6db15c89..0beb961291 100644
--- a/tools/rootcanal/proto/rootcanal/configuration.proto
+++ b/tools/rootcanal/proto/rootcanal/configuration.proto
@@ -24,6 +24,8 @@ enum ControllerPreset {
LAIRD_BL654 = 1;
// Official PTS dongle, CSR rck.
CSR_RCK_PTS_DONGLE = 2;
+ // Official PTS dongle, Intel BE200.
+ INTEL_BE200 = 3;
}
message ControllerFeatures {
diff --git a/tools/rootcanal/scripts/controller_info.py b/tools/rootcanal/scripts/controller_info.py
index 10a74a0daf..cca4f0970b 100755
--- a/tools/rootcanal/scripts/controller_info.py
+++ b/tools/rootcanal/scripts/controller_info.py
@@ -98,66 +98,74 @@ async def br_edr_properties(host: Host):
page2 = await host.expect_evt(hci.ReadLocalExtendedFeaturesComplete)
print(
- f"lmp_features: {{ 0x{page0.lmp_features:x}, 0x{page1.extended_lmp_features:x}, 0x{page2.extended_lmp_features:x} }}"
+ f"lmp_features = {{ 0x{page0.lmp_features:x}, 0x{page1.extended_lmp_features:x}, 0x{page2.extended_lmp_features:x} }};"
)
await host.send_cmd(hci.ReadBufferSize())
evt = await host.expect_evt(hci.ReadBufferSizeComplete)
- print(f"acl_data_packet_length: {evt.acl_data_packet_length}")
- print(f"total_num_acl_data_packets: {evt.total_num_acl_data_packets}")
- print(f"sco_data_packet_length: {evt.synchronous_data_packet_length}")
- print(f"total_num_sco_data_packets: {evt.total_num_synchronous_data_packets}")
+ print(f"acl_data_packet_length = {evt.acl_data_packet_length};")
+ print(f"total_num_acl_data_packets = {evt.total_num_acl_data_packets};")
+ print(f"sco_data_packet_length = {evt.synchronous_data_packet_length};")
+ print(f"total_num_sco_data_packets = {evt.total_num_synchronous_data_packets};")
await host.send_cmd(hci.ReadNumberOfSupportedIac())
evt = await host.expect_evt(hci.ReadNumberOfSupportedIacComplete)
- print(f"num_supported_iac: {evt.num_support_iac}")
+ print(f"num_supported_iac = {evt.num_support_iac};")
async def le_properties(host: Host):
- await host.send_cmd(hci.LeReadLocalSupportedFeatures())
- evt = await host.expect_evt(hci.LeReadLocalSupportedFeaturesComplete)
+ await host.send_cmd(hci.LeReadLocalSupportedFeaturesPage0())
+ evt = await host.expect_evt(hci.LeReadLocalSupportedFeaturesPage0Complete)
- print(f"le_features: 0x{evt.le_features:x}")
+ print(f"le_features = 0x{evt.le_features:x};")
- await host.send_cmd(hci.LeReadBufferSizeV2())
- evt = await host.expect_evt(hci.LeReadBufferSizeV2Complete)
+ try:
+ await host.send_cmd(hci.LeReadBufferSizeV2())
+ evt = await host.expect_evt(hci.LeReadBufferSizeV2Complete)
+
+ print(f"le_acl_data_packet_length = {evt.le_buffer_size.le_data_packet_length};")
+ print(f"total_num_le_acl_data_packets = {evt.le_buffer_size.total_num_le_packets};")
+ print(f"iso_data_packet_length = {evt.iso_buffer_size.le_data_packet_length};")
+ print(f"total_num_iso_data_packets = {evt.iso_buffer_size.total_num_le_packets};")
+
+ except Exception:
+ await host.send_cmd(hci.LeReadBufferSizeV1())
+ evt = await host.expect_evt(hci.LeReadBufferSizeV1Complete)
- print(f"le_acl_data_packet_length: {evt.le_buffer_size.le_data_packet_length}")
- print(f"total_num_le_acl_data_packets: {evt.le_buffer_size.total_num_le_packets}")
- print(f"iso_data_packet_length: {evt.iso_buffer_size.le_data_packet_length}")
- print(f"total_num_iso_data_packets: {evt.iso_buffer_size.total_num_le_packets}")
+ print(f"le_acl_data_packet_length = {evt.le_buffer_size.le_data_packet_length};")
+ print(f"total_num_le_acl_data_packets = {evt.le_buffer_size.total_num_le_packets};")
await host.send_cmd(hci.LeReadFilterAcceptListSize())
evt = await host.expect_evt(hci.LeReadFilterAcceptListSizeComplete)
- print(f"le_filter_accept_list_size: {evt.filter_accept_list_size}")
+ print(f"le_filter_accept_list_size = {evt.filter_accept_list_size};")
await host.send_cmd(hci.LeReadResolvingListSize())
evt = await host.expect_evt(hci.LeReadResolvingListSizeComplete)
- print(f"le_resolving_list_size: {evt.resolving_list_size}")
+ print(f"le_resolving_list_size = {evt.resolving_list_size};")
await host.send_cmd(hci.LeReadSupportedStates())
evt = await host.expect_evt(hci.LeReadSupportedStatesComplete)
- print(f"le_supported_states: 0x{evt.le_states:x}")
+ print(f"le_supported_states: 0x{evt.le_states:x};")
await host.send_cmd(hci.LeReadMaximumAdvertisingDataLength())
evt = await host.expect_evt(hci.LeReadMaximumAdvertisingDataLengthComplete)
- print(f"le_max_advertising_data_length: {evt.maximum_advertising_data_length}")
+ print(f"le_max_advertising_data_length = {evt.maximum_advertising_data_length};")
await host.send_cmd(hci.LeReadNumberOfSupportedAdvertisingSets())
evt = await host.expect_evt(hci.LeReadNumberOfSupportedAdvertisingSetsComplete)
- print(f"le_num_supported_advertising_sets: {evt.number_supported_advertising_sets}")
+ print(f"le_num_supported_advertising_sets = {evt.number_supported_advertising_sets};")
await host.send_cmd(hci.LeReadPeriodicAdvertiserListSize())
evt = await host.expect_evt(hci.LeReadPeriodicAdvertiserListSizeComplete)
- print(f"le_periodic_advertiser_list_size: {evt.periodic_advertiser_list_size}")
+ print(f"le_periodic_advertiser_list_size = {evt.periodic_advertiser_list_size};")
async def run(tcp_port: int):
@@ -170,16 +178,16 @@ async def run(tcp_port: int):
await host.send_cmd(hci.ReadLocalVersionInformation())
evt = await host.expect_evt(hci.ReadLocalVersionInformationComplete)
- print(f"hci_version: {evt.local_version_information.hci_version}")
- print(f"hci_subversion: 0x{evt.local_version_information.hci_revision:x}")
- print(f"lmp_version: {evt.local_version_information.lmp_version}")
- print(f"lmp_subversion: 0x{evt.local_version_information.lmp_subversion:x}")
- print(f"company_identifier: 0x{evt.local_version_information.manufacturer_name:x}")
+ print(f"hci_version = {evt.local_version_information.hci_version};")
+ print(f"hci_subversion = 0x{evt.local_version_information.hci_revision:x};")
+ print(f"lmp_version = {evt.local_version_information.lmp_version};")
+ print(f"lmp_subversion = 0x{evt.local_version_information.lmp_subversion:x};")
+ print(f"company_identifier = 0x{evt.local_version_information.manufacturer_name:x};")
await host.send_cmd(hci.ReadLocalSupportedCommands())
evt = await host.expect_evt(hci.ReadLocalSupportedCommandsComplete)
- print(f"supported_commands: {{ {', '.join([f'0x{b:x}' for b in evt.supported_commands])} }}")
+ print(f"supported_commands = {{ {', '.join([f'0x{b:02x}' for b in evt.supported_commands])} }};")
try:
await br_edr_properties(host)